A, what is automatic packing and unpacking is very simple, the following two lines of code can see the packing and unpacking process
1 // Automatic packing 2 Integer total = 99; 5 int totalprim = total;Copy the code
Simply put, boxing automatically converts the base data type to the wrapper type; Unpacking automatically converts wrapper types to primitive data types.
Let’s take a look at the types of packing and unpacking:
This process is automated, so we need to look at its execution:
1 public class Main {2 public static void Main (String[] args) {3 Integer total = 99; 7 int totalprim = total; 9 8}}Copy the code
Decompiling the class file yields the following:
1 javap -c StringTest
Integer total = 99; Integer total = integer.valueof (99);
int totalprim = total; Int totalPrim = total.intValue();
ValueOf (Integer, valueOf); valueOf (Integer, valueOf, valueOf)
1 public static Integer valueOf(int i) { 2 return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128]; 3}Copy the code
It first determines the size of I: if I is less than -128 or greater than or equal to 128, an Integer object is created, otherwise SMALL_VALUES[I + 128] is executed.
First let’s look at the Integer constructor:
1 private final int value; 2 3 public Integer(int value) { 4 this.value = value; 5 } 6 7 public Integer(String string) throws NumberFormatException { 8 this(parseInt(string)); 9}Copy the code
It defines a value variable, and when you create an Integer object, you initialize that variable. The second one is a String variable, which it first converts to an int value and then initializes.
SMALL_VALUES[I + 128]
1 private static final Integer[] SMALL_VALUES = new Integer[256]; Copy the code
It’s a static Integer array object, which means that valueOf ultimately returns an Integer object.
So we can sum up one point here: the process of packing will create corresponding objects, which consumes memory, so the process of packing will increase memory consumption, affecting performance.
2. Then look at the intValue function
1 @Override 2 public int intValue() { 3 return value; 4}Copy the code
This is easy, just return value.
As we have seen above, the Integer constructor has two cases:
1, I > = 128 | | I = = = = = > < – 128 new Integer (I) 2, I < 128 && I > = 128 = = = = = > SMALL_VALUES [I + 128]
1 private static final Integer[] SMALL_VALUES = new Integer[256];Copy the code
SMALL_VALUES already be created, that is to say the I > = 128 | | I < – 128 is will create different objects, in I < 128 && I > = 128 will return according to the value of the I already created good the specified object.
Let’s take a look at this.
1 public class Main {
2 public static void main(String[] args) {
3
4 Integer i1 = 100;
5 Integer i2 = 100;
6 Integer i3 = 200;
7 Integer i4 = 200;
8
9 System.out.println(i1==i2); //true
10 System.out.println(i3==i4); //false
11 }
12 }Copy the code
Later in the code, we can see that their execution results are different. Why? Look at our instructions above. 1, i1, and i2 are automatically boated, valueOf is executed, and their values are in the range (-128,128). They get the same object SMALL_VALUES[228] in the SMALL_VALUES array. They reference the same Integer object. So they must be equal.
2, i3, and I4 are also auto-boxing, valueOf is executed, and their values are greater than 128, so new Integer(200) is executed, which means they create two different objects, so they must not be equal.
Let’s look at another example:
1 public class Main {2 public static void Main (String[] args) {3 4 Double i1 = 100.0; 5 Double i2 = 100.0; 6 Double i3 = 200.0; 7 Double i4 = 200.0; 8 9 System.out.println(i1==i2); //false 10 System.out.println(i3==i4); //false 11 } 12 }Copy the code
If you look at the above results, they are not the same as Integer, which is not surprising, because their valueOf implementations are different, so why not unify them? This makes sense, because for integers, there are only 256 fixed values between (-128,128), so to avoid creating objects more than once, we create an Integer array SMALL_VALUES of 256, so if the values are within this range, We can just return the object that we created in advance.
But for Double, we can’t do that, because it’s infinite in this range. The number of integer values in a range is finite, but floating-point values are not.
So inside a Double it’s pretty straightforward, you just create an object, so you create a different object every time.
1 public static Double valueOf(double d) { 2 return new Double(d); 3}Copy the code
Integer classes: valueOf methods of Integer, Short, Byte, Character, and Long are implemented similarly. Double: The implementation of the valueOf methods for Double and Float is similar. A different object is returned each time.
Here’s a summary of the Integer faction, as shown below:
Let’s look at another case:
1 public class Main { 2 public static void main(String[] args) { 3 4 Boolean i1 = false; 5 Boolean i2 = false; 6 Boolean i3 = true; 7 Boolean i4 = true; 8 9 System.out.println(i1==i2); //true 10 System.out.println(i3==i4); //true 11 } 12 }Copy the code
You can see that they all return true, that is, they all return the same object when valueOf is executed.
1 public static Boolean valueOf(boolean b) { 2 return b ? Boolean.TRUE : Boolean.FALSE; 3}Copy the code
You can see that it doesn’t create objects, because internally it creates two objects ahead of time, because it only has two cases, again to avoid creating too many objects repeatedly.
1 public static final Boolean TRUE = new Boolean(true);
2
3 public static final Boolean FALSE = new Boolean(false);Copy the code
Several of these cases have been described above, and the rest are discussed further below.
1 Integer num1 = 400;
2 int num2 = 400;
3 System.out.println(num1 == num2); //trueCopy the code
Num1 == NUM2 is unpackedCopy the code
1 Integer num1 = 100;
2 int num2 = 100;
3 System.out.println(num1.equals(num2)); //trueCopy the code
Let’s take a look at equals source:
1 @Override 2 public boolean equals(Object o) { 3 return (o instanceof Integer) && (((Integer) o).value == value); 4}Copy the code
We specify equal to compare the content itself, and we can also see that the argument to equal is an Object, we pass in an int, so it’s first boated, then compared, and returns true because it compares the value inside the Object.
1 Integer num1 = 100;
2 int num2 = 100;
3 Long num3 = 200l;
4 System.out.println(num1 + num2); //200
5 System.out.println(num3 == (num1 + num2)); //true
6 System.out.println(num3.equals(num1 + num2)); //falseCopy the code
1. When a base data type and the encapsulated class perform operations of ==, +, -, * and /, the encapsulated class will be unpacked and the basic data type will be calculated. Num3. Equals (num1 + num2) = false
1 @Override 2 public boolean equals(Object o) { 3 return (o instanceof Long) && (((Long) o).value == value); 4}Copy the code
It must satisfy two conditions to be true: 1. Same type; 2. Same content.
1 Integer num1 = 100;
2 Ingeger num2 = 200;
3 Long num3 = 300l;
4 System.out.println(num3 == (num1 + num2)); //trueCopy the code
Let’s decompile some of this class file: javap -c StringTest
Num1: intValue (num1: intValue (num2: intValue)); mum2: intValue (num1: intValue); And then do the basic operations.
Let’s test the base type:
1 int num1 = 100;
2 int num2 = 200;
3 long mum3 = 300;
4 System.out.println(num3 == (num1 + num2)); //trueCopy the code
That explains why the top returns true.
So, when both operands of the “==” operator are references to wrapper types, they are compared to refer to the same object, whereas if one of the operands is an expression (that is, contains arithmetic operations) they are compared to a value (that is, triggers automatic unboxing).
Trap 1:
1 Integer integer100=null;
2 int int100=integer100;Copy the code
These two lines of code are perfectly legal and perfectly compilable, but at run time, null-pointer exceptions are thrown. Where integer100 is an object of type Integer, which of course can point to NULL. On the second line, however, integer100 is unboxed, that is, intValue() on a null object, which of course throws a nullpointer exception. Therefore, when unpacking, pay special attention to whether the encapsulated class object is null.
Conclusion: 1, need to know when will trigger packing and unpacking 2, packing operation will create objects, frequent packing operation will consume a lot of memory, affect performance, so can avoid packing should be avoided.
Because the parameter type in equals is the wrapper type, the parameter type (a) passed to equals is the original data type, so it is automatically boxed, otherwise it is unboxed
4. When two different types are compared with ==, the wrapper class needs to be unpacked. When the same type is compared with ==, it will be automatically unpacked or packed