(Turn) In-depth analysis of boxing and unboxing in Java

Transfer: https://www.cnblogs.com/dolphin0520/p/3780005.html

Deep dive into boxing and unboxing in Java

  The problem of automatic boxing and unboxing is a common problem in Java. Today we will take a look at some of the problems in boxing and unboxing. This article first describes the most basic things about packing and unpacking, and then takes a look at the problems related to packing and unpacking that are often encountered in the interview written test.

  Here is the table of contents outline for this article:

  1. What is packing? What is unboxing?

  2. How packing and unpacking are implemented

  3. Questions related to the interview

1. What is packing? What is unboxing?

  As mentioned in the previous article, Java provides a corresponding wrapper type for each basic data type. As for why a wrapper type is provided for each basic data type, I will not elaborate here. Interested friends can refer to the relevant material. Before Java SE5, if you wanted to generate an Integer object with a value of 10, you had to do it like this:

1
Integer i =  new  Integer( 10 );

  Since Java SE5 has provided the feature of automatic boxing, if you want to generate an Integer object with a value of 10, you only need to do this:

1
Integer i =  10 ;

  In this process, the corresponding Integer object is automatically created according to the value, which is boxing.

  So what is unboxing? As the name implies, it corresponds to boxing, which is to automatically convert the wrapper type to the basic data type:

1
2
Integer i =  10 ;   //装箱
int  n = i;    //拆箱

  Simply put, boxing is to automatically convert the basic data type to a wrapper type; unboxing is to automatically convert the wrapper type to a basic data type.

  The following table is the wrapper type corresponding to the basic data type:

int (4 bytes) Integer
byte (1 byte) Byte
short (2 bytes) Short
long (8 bytes) Long
float (4 bytes) Float
double (8 bytes) Double
char (2 bytes) Character
boolean (undecided) Boolean

2. How packing and unpacking are implemented

  After understanding the basic concepts of boxing in the previous section, let's take a look at how boxing and unboxing are implemented in this section.

  Let's take the Interger class as an example. Let's look at a piece of code:

1
2
3
4
5
6
7
public  class  Main {
     public  static  void  main(String[] args) {
         
         Integer i =  10 ;
         int  n = i;
     }
}

  After decompiling the class file, the following content is obtained:

  

  As can be seen from the bytecode content obtained by decompilation, the valueOf(int) method of Integer is automatically called during boxing. When unboxing, the intValue method of Integer is automatically called.

  Others are similar, such as Double, Character, and friends who don't believe it can try it manually.

  Therefore, the implementation process of boxing and unboxing can be summarized in one sentence:

  The boxing process is implemented by calling the valueOf method of the wrapper, and the unboxing process is implemented by calling the xxxValue method of the wrapper. (xxx represents the corresponding basic data type).

3. Questions related to the interview

  Although most people are clear about the concept of boxing and unboxing, they may not be able to answer the questions related to boxing and unboxing in interviews and written tests. Below are some common interview questions related to packing/unpacking.

1. What is the output of the following code?

1
2
3
4
5
6
7
8
9
10
11
12
public  class  Main {
     public  static  void  main(String[] args) {
         
         Integer i1 =  100 ;
         Integer i2 =  100 ;
         Integer i3 =  200 ;
         Integer i4 =  200 ;
         
         System.out.println(i1==i2);
         System.out.println(i3==i4);
     }
}

  Maybe some friends will say that they will output false, or some friends will say that they will output true. But in fact the output is:

true
false

   Why does this result occur? The output shows that i1 and i2 point to the same object, while i3 and i4 point to different objects. At this point, you only need to look at the source code to find out. The following code is the specific implementation of Integer's valueOf method:

public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) return IntegerCache.cache[i + 128]; else return new Integer(i); }

  The implementation of the IntegerCache class is:

copy code
 private static class IntegerCache { static final int high; static final Integer cache[]; static { final int low = -128; // high value may be configured by property int h = 127; if (integerCacheHighPropValue != null) { // Use Long.decode here to avoid invoking methods that // require Integer's autoboxing cache to be initialized int i = Long.decode(integerCacheHighPropValue).intValue(); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - -low); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }
copy code

  As can be seen from these two pieces of code, when creating an Integer object through the valueOf method, if the value is between [-128, 127], it returns a reference to an object that already exists in IntegerCache.cache; otherwise, a new Integer object is created .

  In the above code, the value of i1 and i2 is 100, so the existing objects will be taken directly from the cache, so i1 and i2 point to the same object, while i3 and i4 point to different objects respectively.

2. What is the output of the following code?

1
2
3
4
5
6
7
8
9
10
11
12
public  class  Main {
     public  static  void  main(String[] args) {
         
         Double i1 =  100.0 ;
         Double i2 =  100.0 ;
         Double i3 =  200.0 ;
         Double i4 =  200.0 ;
         
         System.out.println(i1==i2);
         System.out.println(i3==i4);
     }
}

  Some friends may think that the output result of the above question is the same, but in fact it is not. The actual output is:

false
 false

  As for the specific reason, readers can check the implementation of valueOf of the Double class.

  Here only explain why the valueOf method of the Double class adopts a different implementation from the valueOf method of the Integer class. Simple: the number of integer values ​​in a range is finite, while floating point numbers are not.

  Note that the implementation of the valueOf method of the Integer, Short, Byte, Character, and Long classes is similar.

     The implementation of the valueOf method of Double and Float is similar.

3. What is the output of the following code:

1
2
3
4
5
6
7
8
9
10
11
12
public  class  Main {
     public  static  void  main(String[] args) {
         
         Boolean i1 =  false ;
         Boolean i2 =  false ;
         Boolean i3 =  true ;
         Boolean i4 =  true ;
         
         System.out.println(i1==i2);
         System.out.println(i3==i4);
     }
}

  The output is:

true
true

  As for why this is the result, similarly, the source code of the Boolean class will be clear at a glance. The following is the specific implementation of Boolean's valueOf method:

public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }

  And what are TRUE and FALSE among them? There are 2 static member properties defined in Boolean:

copy code
 public static final Boolean TRUE = new Boolean(true); /** * The <code>Boolean</code> object corresponding to the primitive * value <code>false</code>. */ public static final Boolean FALSE = new Boolean(false);
copy code

  At this point, everyone should understand why the above output results are true.

4. Talk about the difference between Integer i = new Integer(xxx) and Integer i =xxx;.

  Of course, this topic is of a broader type. But the main points must be answered. I summarize the main differences as follows:

  1) The first method will not trigger the process of autoboxing; while the second method will trigger;

  2) Differences in execution efficiency and resource occupancy. The execution efficiency and resource consumption of the second method are generally better than the first case (note that this is not absolute).

5. What is the output of the following program?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public  class  Main {
     public  static  void  main(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;
         
         System.out.println(c==d);
         System.out.println(e==f);
         System.out.println(c==(a+b));
         System.out.println(c.equals(a+b));
         System.out.println(g==(a+b));
         System.out.println(g.equals(a+b));
         System.out.println(g.equals(a+h));
     }
}

  Don't look at the output first, the reader thinks about what the output of this code is. It should be noted here that when the two operands of the "==" operator are references of the wrapper type, the comparison points to the same object, and if one of the operands is an expression (ie. contains arithmetic operations) compares values ​​(that is, triggers an automatic unboxing process). Also, for wrapper types, the equals method does not perform type conversions. After understanding these two points, the above output results are clear at a glance:

copy code
true
false
true
true true false true
copy code

  There is no doubt about the first and second output results. The third sentence will trigger the automatic unboxing process (the intValue method will be called) because a+b contains arithmetic operations, so they compare whether the values ​​are equal. For c.equals(a+b), the automatic unboxing process will be triggered first, and then the automatic boxing process will be triggered. That is to say, a+b will call the intValue method first, and after the value after the addition operation is obtained, it will call the Integer.valueOf method, and then compare equals. The same is true for the latter, but pay attention to the results of the penultimate and last output (if the value is of type int, the boxing process calls Integer.valueOf; if it is of type long, the Long called by boxing .valueOf method).

If you have any questions about the specific execution process above, you can try to obtain the decompiled bytecode content for viewing.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325185361&siteId=291194637