Overview
Since the beginning of the JDK1.5, the syntactic sugar of automatic boxing/unpacking has been introduced, which makes the programmer's code more concise and eliminates the need for explicit conversions. Basic type and wrapper type under the action of some operators, the wrapper type calls the ValueOf () method to convert the original type value into the corresponding wrapper class object, called Automatic boxing; Conversely, the process of calling the Xxxvalue () method to convert a wrapper class object to a primitive type value is called an automatic unboxing.
Implementation Principle
First we use the javap-c autoboxingdemo command to decompile the following code :
Public class Autoboxingdemo { publicstaticvoid main (string[] args) { = 1 ; int n = m; }}
Post-compilation results:
As can be seen from the anti-compiled bytecode directive, Integer m = 1 , in fact, the bottom is called the wrapper class Integer valueof () method for automatic boxing, and int n = m; The layer invokes the wrapper class's Intvalue () method for automatic unpacking.
Where byte, short, Integer, Long, Boolean, character these six packaging types are used in automatic boxing, the cache policy, the following is the cache implementation mechanism of the Integer class:
/*** This method would always have the cache values in the range-128 to 127, * inclusive, and could cache other values outside of T His range. */ Public StaticInteger ValueOf (inti) {assertIntegercache.high >= 127; if(I >= integercache.low && i <=Integercache.high)returnIntegercache.cache[i + (-Integercache.low)]; return NewInteger (i);}Private Static classIntegercache {Static Final intLow =-128; Static Final intHigh ; Static FinalInteger cache[]; Static { //High value is configured by property intH = 127; String Integercachehighpropvalue=Sun.misc.VM.getSavedProperty ("Java.lang.Integer.IntegerCache.high"); if(Integercachehighpropvalue! =NULL) { inti =parseint (Integercachehighpropvalue); I= Math.max (i, 127); //Maximum array size is Integer.max_valueh = math.min (i, Integer.max_value-(-low)-1); } High=h; Cache=Newinteger[(high-low) + 1]; intj =Low ; for(intk = 0; K < Cache.length; k++) Cache[k]=NewInteger (j + +); } PrivateIntegercache () {}}
From the source code of the integer we can tell that when the value of auto-boxing is between [-128, 127], the call to the valueof () method returns an object reference that already exists in the integer cache. Otherwise, each time it is a new wrapper class instance.
Double, float, two types of packing because it is a floating-point number, unlike integers in a range of numeric values is limited, so they do not use the cache implementation mechanism, the following is a double wrapper class automatic boxed source code:
Public Static Double valueOf (double d) { returnnew double (d);}
examples Show
Public classAutoboxingdemo { Public Static voidMain (string[] args) {Integer a= 1; Integer b= 2; Integer C= 3; Integer D= 3; Integer e= 321; Integer F= 321; Long g= 3L; Long h= 2L; Double I= 1.0; Double J= 1.0; Boolean k=true; Boolean L=true;
//values in the range of [-128, 127] are automatically boxed when the object reference is obtained from the cache, so the result is trueSystem.out.println (c==d); //value is outside the range of [-128, 127], and is automatically boxed each time it is a new object, so the result is falseSystem.out.println (e==f); //when the two operand of the "= =" operator is a reference to the wrapper type, the comparison points to whether the same object is the same, and if one of the operands is an expression (that is, the arithmetic operation is included), the value is compared (that is, the process that triggers the automatic unboxing), so the result is trueSystem.out.println (c== (A +b)); //for wrapper types, when the Equals () method compares the same type (for example, Integer vs. integer), the actual comparison is whether their values are equal. If the comparison is not of the same type, the type conversion is not performed and returns false directly. So the result is trueSystem.out.println (C.equals (A +b)); //because there are arithmetic operations, automatic unpacking and then comparing values, so the result is trueSystem.out.println (g== (A +b)); //because the Equals () method compares different wrapper types, no type conversions are made, so the result is falseSystem.out.println (G.equals (A +b)); //because the a+h first triggers the automatic unpacking, a to int type, you need to implicitly raise the type long after the operation, and then automatically boxed into a long wrapper type, and the two sides of the value is equal, so the result is trueSystem.out.println (G.equals (A +h)); //The double class has no cache, and each time it is a new instance, so the result is falseSystem.out.println (i = =j); //Boolean Auto-boxing, pointing to the same instance, so the result is trueSystem.out.println (k = =l); }}
In the above example, the analysis of the results is clear, there are two main areas of confusion. When the two operand of the "= =" operator is a reference to the wrapper type, the comparison points to whether the same object is the same, and if one of the operands is an expression (that is, the arithmetic operation is included), the value is compared (that is, the process of automatically unpacking is triggered first).
For wrapper types, when the Equals () method compares the same type (for example, Integer vs. integer), the actual comparison is whether their values are equal; If the comparison is not of the same type (for example, integer versus long), then the type conversion is not performed and returns false directly. The following is the source code for the Equals () method of the integer class:
Public Boolean equals (Object obj) { ifinstanceof Integer) { return value = = ((Integer) obj). Intvalue (); } return false ;}
In addition, we can decompile the above code, through the icing of the grammar sugar can help us to understand these confusing phenomenon behind the principle:
problems with automatic packing/unpacking
null pointer problem caused by arithmetic operation in automatic unpacking
Private Double distinct; Private void Boolean flag) { this. Distinct = (flag)? dsrc:0d;}
The above code is fine at first glance, but actually when DSRC is null, calling the method throws a null pointer exception, which we decompile:
As you can see, when you perform arithmetic operations such as a trinocular operator on a wrapper class, when the data type is inconsistent, the compiler automatically splits the box into the base type and then the operation, so when DSRC passes in a null value, the call to the Doublevalue () method will report the NP null pointer exception.
Here we can solve the problem of NULL pointer for the three-mesh operator in unpacking by unifying the data type and avoiding the compiler to do the automatic unpacking in the arithmetic operation. Or the chestnut above, we will this . Distinct = (flag)? dsrc:0d; modified to this . Distinct = (flag)? Dsrc:doubl e.valueof (0); Can be resolved, re-decompile as follows, because the type is the same, no more automatic unpacking:
the drawbacks of automatic boxing
Integer sum = 0for (int i=1000; i<10000; i++) { sum+ =i;}
As the above code, when the wrapper type in the loop arithmetic operation sum = sum + i , will trigger the automatic unpacking, after the addition operation, and then automatic boxing, and because the sum value after the operation is not within the cache range, so each time will be a new integer real Cases. So when the above loop is over, it will create 9,000 useless integer instance objects in memory, which will greatly reduce the performance of the program and increase the cost of GC, so we must declare the variable type correctly when we write the loop statement, and avoid unnecessary performance problems caused by automatic boxing.
heavy and automatic boxing
Before JDK1.5, the syntactic sugar of automatic boxing/unpacking was not introduced, and when the method was overloaded, test (int num) had no relation to the parameters of test (Integer num) . After JDK1.5, when the overloaded method is called, the compiler does not do an auto-boxing operation, which we can demonstrate by running the following code example.
Public Static void testautoboxing (int num) { System.out.println ("method parameter is original type");} Public Static void testautoboxing (Integer num) { System.out.println ("method parameter is wrapper type");} Public Static void Main (string[] args) { int m = 2; Testautoboxing (m); = m; Testautoboxing (n);}
The results of the operation are as follows:
Obviously, when an overloaded method is called, the compiler does not automatically boxing the incoming arguments.
Resources
Autoboxing and Unboxing (the Java tutorials > Lea ...
In-depth analysis of boxing and unboxing in Java-haizi-Blog Park
Java Automatic Boxing and unpacking implementation principle-Pinterest
The unspoken rules of the trinocular operator under the Java automatic unpacking
Automatic boxing and unpacking in Java
Automatic packing/unpacking in Java