Preface
This article mainly introduces relevant content about Integer in Java, and shares it for your reference and learning. I won’t say much below, let’s take a look at the detailed introduction together.
Real parasites
A few days ago, I saw an article shared by my Moments "The Parameter Transmission Mechanism of Java Functions - Do you really understand it? 》
Some triggers have been studied in Java's Integer before, so I wrote this article, hoping it will be helpful to you.
exchange
Let’s first look at an example.
Please use Java to complete the swap function and exchange values of two integer types.
public static void test() throws Exception { Integer a = 1, b = 2; swap(a, b); System.out.println("a=" + a + ", b=" + b);}static void swap(Integer a, Integer b){ // Parts that need to be implemented} first
If you don't understand how Java objects are allocated in memory and how methods pass parameters, you may write the following code.
public static void swapOne(Integer a, Integer b) throws Exception { Integer aTempValue = a; a = b; b = aTempValue;} The results of the run show that the values a and b are not exchanged.
So let's take a look at how Java objects are allocated in memory when the above program runs:
Object address assignment
From this we can see that the local variable tables of the two methods hold references to the actual data addresses of objects a and b.
The swap function implemented above only exchanges references to local variable a and local variable b in the swap function, and does not exchange the actual data in the JVM heap.
Therefore, the data referenced by a and b in the main function is not exchanged, so the a and b of the local variables in the main function will not change.
So how do you operate when exchanging the data in the main function?
The second time
According to the above practice, can we consider exchanging data values of a and b on the JVM heap?
Let’s briefly learn about the Integer object. It only has an object-level int value to represent the value of the object.
So we use reflection to modify the value, the code is as follows:
public static void swapTwo(Integer a1, Integer b1) throws Exception { Field valueField = Integer.class.getDeclaredField("value"); valueField.setAccessible(true); int tempAValue = valueField.getInt(a1); valueField.setInt(a1, b1.intValue()); valueField.setInt(b1, tempAValue);}The operation results are in line with expectations.
surprise
After the above program is run, what will happen if I declare an Integer c = 1, d = 2;
The sample program is as follows:
public static void swapTwo(Integer a1, Integer b1) throws Exception { Field valueField = Integer.class.getDeclaredField("value"); valueField.setAccessible(true); int tempAValue = valueField.getInt(a1); valueField.setInt(a1, b1.intValue()); valueField.setInt(b1, tempAValue);}public static void testThree() throws Exception { Integer a = 1, b = 2; swapTwo(a, b); System.out.println("a=" + a + "; b=" + b); Integer c = 1, d = 2; System.out.println("c=" + c + "; d=" + d);}The output results are as follows:
a=2; b=1c=2; d=1
Surprise or not! Accident or not! Stimulating or not!
In-depth
What exactly happened? Let's take a look at the decompiled code:
The author used the IDE tool to directly decompile this .class file
public static void testThree() throws Exception { Integer a = Integer.valueOf(1); Integer b = Integer.valueOf(2); swapTwo(a, b); System.out.println("a=" + a + "; b=" + b); Integer c = Integer.valueOf(1); Integer d = Integer.valueOf(2); System.out.println("c=" + c + "; d=" + d);} In the process of Java automatically boxing the original type int to the Integer type Integer.valueOf(int) method is used.
It must be that this method encapsulates some operations internally, which causes us to have a global impact after modifying Integer.value .
All this involves the code in this part of the code is glued at once (PS: the author who does not drag is a good coder):
public class Integer{ /** * @since 1.5 */ public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} } As shown above, Integer has a private static class IntegerCache inside, which statically initializes an Integer array containing Integer.IntegerCache.low to java.lang.Integer.IntegerCache.high .
The value range of java.lang.Integer.IntegerCache.high is between [127~Integer.MAX_VALUE - (-low) -1] .
All objects returned by the Integer.valueOf(int) function in this interval are offsets calculated based on the int value and are obtained from the array Integer.IntegerCache.cache . The object is the same and no new object is created.
So when we modify the value of Integer.valueOf(1) , all the return values of Integer.IntegerCache.cache[ 1 - IntegerCache.low ] will be changed.
I believe your IQ should be understood. If you don’t understand, please call 10086 in the comment section.
OK, so what about the part that is not in [IntegerCache.low~IntegerCache.high) ?
Obviously, they are lucky, not cached by IntegerCache, and every time they arrive, they will allocate a piece of earth (inland) (distribution) on the JVM.
Reverie
What if I change the converted parameter to type to int?
public static void testOne() throws Exception { int a = 1, b = 2; swapOne(a, b); System.out.println("a=" + a + ", b=" + b);}static void swapOne(int a, int b){ // Parts that need to be implemented} With the author's current skills, there is no solution. Experts can leave messages on the official account, thank you very much!
So far, the swap part has been finished.
1 + 1
First let's look at the code:
public static void testOne() { int one = 1; int two = one + one; System.out.printf("Two=%d", two);} What is the output?
If you say 2 to be sure, then you have learned it in vain, please call 95169 directly.
I can tell you for sure that it can be any value in the [Integer.MIN_VALUE~Integer.MAX_VALUE] interval.
Surprise or not! Accident or not! Stimulating or not!
Let’s stroke the roast code one by one.
The author used the IDE tool to directly decompile this .class file
public static void testOne() { int one = 1; int two = one + one; System.out.printf("Two=%d", two);} The variable two here did not call In teger.valueOf(int) , which is different from what I imagined. I suspect this is the IDE's pot.
So check the compiled bytecode decisively. The following are some of the bytecodes of the excerpt:
LDC "Two=%d"ICONST_1ANEWARRAY java/lang/ObjectDUPICONST_0ILOAD 2INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;AASTOREINVOKEVIRTUAL java/io/PrintStream.printf (Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;POP
It can be seen that it is indeed the IDE's pot. Not only is Integer.valueOf(int) called once, but an array of Object is also created.
The complete Java code should look like this:
public static void testOne() { int one = 1; int two = one + one; Object[] params = { Integer.valueOf(two) }; System.out.printf("Two=%d", params);} So just modify the value of Integer.IntegerCache.cache[2+128] before the method is called, so add some code to the static initialization part of the class.
public class OnePlusOne { static { try { Class<?> cacheClazz = Class.forName("java.lang.Integer$IntegerCache"); Field cacheField = cacheClazz.getDeclaredField("cache"); cacheField.setAccessible(true); Integer[] cache = (Integer[]) cacheField.get(null); //Change here to 1 + 1 = 3 cache[2 + 128] = new Integer(3); } catch (Exception e) { e.printStackTrace(); } } public static void testOne() { int one = 1; int two = one + one; System.out.printf("Two=%d", two); }}two == 2 ?
After modifying the value of Integer.IntegerCache.cache[2 + 128] , is the variable two equal to 2?
public static void testTwo() { int one = 1; int two = one + one; System.out.println(two == 2); System.out.println(Integer.valueOf(two) == 2);}The above code output is as follows
truefalse
Because two == 2 does not involve the conversion of Integer boxing, or a comparison of the original type, the 2 of the original type is always equal to 2.
The real form of Integer.valueOf(two)==2 is Integer.valueOf(two).intValue == 2 , that is, 3==2, so it is false.
Here we can see that if you compare a value of null with an Integer variable with an int variable with a double equal sign, a NullPointException will be thrown.
What kind of output will be if the method here is replaced by System.out.println("Two=" + two) ? You can try it.
postscript
XCache
| kind | Is there a Cache | Minimum value | Maximum value |
|---|---|---|---|
| Boolean | none | -- | -- |
| Byte | ByteCache | -128 | 127(fixed) |
| Short | ShortCache | -128 | 127(fixed) |
| Character | CharacterCache | 0 | 127(fixed) |
| Integer | IntegerCache | -128 | java.lang.Integer.IntegerCache.high |
| Long | LongCache | -128 | 127(fixed) |
| Float | none | -- | -- |
| Double | none | -- | -- |
java.lang.Integer.IntegerCache.high
After reading the method of obtaining high sun.misc.VM.getSavedProperty the IntegerCache class, you may have the following questions. We will not delay and use a one-question-one-answer method.
1. How to pass this value into the JVM?
Like the system properties, when JVM is started, it is passed in by setting -Djava.lang.Integer.IntegerCache.high=xxx .
2. What is the difference between this method and System.getProperty ?
In order to distinguish the parameters required by the JVM system from the parameters used by the user,
When java.lang.System.initializeSystemClass is started, the startup parameters will be saved in two places:
2.1 The system parameters received by all JVMs are saved in sun.misc.VM.savedProps.
When the JVM starts, it calls the java.lang.System.initializeSystemClass method to initialize the property.
At the same time, the sun.misc.VM.saveAndRemoveProperties method will also be called to delete the following properties from java.lang.System.props :
The properties listed above are all system parameters that need to be set for JVM startup, so for security considerations and isolation considerations, separate them from the user-accessible System.props.
2.2 Save other parameters except the following parameters required for JVM startup in java.lang.System.props.
PS: JDK 1.8.0_91 used by the author
IntegerCache for Java 9
Imagine if the above naughty gameplay appears in the third-party dependency package, there will definitely be a group of programmers who will go crazy (please don’t try such a bad gameplay, the consequences are very serious).
Fortunately, Java 9 has restricted this. You can write module-info.java file in the corresponding module, which restricts the use of reflection to access members, etc. After declaration as needed, the code can only access fields, methods and other information that can be accessed by reflection. Only when the class is in the same module, or the module has opened a package for reflection access. For details, please refer to the article:
Modify IntegerCache in Java 9?
Thanks to Lydia and Asuka for their valuable advice and hard work on proofreading.
Finally, I would like to share with you a problem that I don’t pay attention to integer value in java:
Let's take a look at a code snippet:
public static void main(String[] args) { Integer a1 = Integer.valueOf(60); //danielinbiti Integer b1 = 60; System.out.println("1:="+(a1 == b1)); Integer a2 = 60; Integer b2 = 60; System.out.println("2:="+(a2 == b2)); Integer a3 = new Integer(60); Integer b3 = 60; System.out.println("3:="+(a3 == b3)); Integer a3 = new Integer(60); Integer b3 = 60; System.out.println("3:="+(a3 == b3)); Integer a4 = 129; Integer b4 = 129; System.out.println("4:="+(a4 == b4)); } If the comparison result of this code is not executed, I don’t know what the answers are in your mind.
To know this answer, it involves the Java buffer and heap issues.
In Java, the Integer type is a buffer for numbers between -128-127, so it is consistent with the equal sign. But for numbers not in this range, they are new in the heap. Therefore, the address space is different, so it is not equal.
Integer b3=60 , this is a packing process, that is, Integer b3=Integer.valueOf(60)
Therefore, in the future, when you encounter Integer, you need to use intValue() to compare whether the values are equal.
There is no buffer for Double.
Answer
1:=true
2:=true
3:=false
4:=false
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.