What is automatic packing and unpacking?
Very simple, you can see the packing and unpacking process in the following two sentences of code
//Automatic packing Integer total = 99; //Automatic unpacking int totalprim = total;
To put it simply, boxing is to automatically convert the basic data type to the wrapper type; Unpacking is to automatically convert the wrapper type to the basic data type.
Let's take a look at the types of packing and unpacking:
This process is automatically executed, so we need to look at its execution process:
Decompile the class file to get the following:
1 javap -c StringTest
Integer total = 99;
When executing the above code, the system executes for us:
Integer total = Integer.valueOf(99);
int totalprim = total;
When executing the above code, the system executes for us:
int totalprim = total.intValue();
Let's take Integer as an example to analyze its source code:
1. First, let's look at the Integer.valueOf function
public class Main { public static void main(String[] args) { //Automatic packing Integer total = 99; //Custom unpacking int totalprim = total; } }
It will first determine the size of I: if I is less than - 128 or greater than or equal to 128, create an Integer object, otherwise execute SMALL_VALUES[i + 128].
First, let's look at the constructor of Integer:
private final int value; public Integer(int value) { this.value = value; } public Integer(String string) throws NumberFormatException { this(parseInt(string)); }
It defines a value variable. If you create an Integer object, you will initialize this variable. The second passed in is a String variable, which will first convert it to an int value and then initialize it.
Let's take a look at small_ What are values [i + 128]:
1 private static final Integer[] SMALL_VALUES = new Integer[256];
It is a static Integer array object, that is, the final valueOf returns an Integer object.
So we can summarize here: the boxing process will create corresponding objects, which will consume memory, so the boxing process will increase memory consumption and affect performance.
2. Then look at the intValue function
@Override public int intValue() { return value; }
This is very simple. Just return the value directly.
Related issues
As we can see above, in the constructor of Integer, it can be divided into two cases:
1,i >= 128 || i < -128 =====> new Integer(i) 2,i < 128 && i >= -128 =====> SMALL_VALUES[i + 128]
private static final Integer[] SMALL_VALUES = new Integer[256];
SMALL_VALUES have already been created, that is, different objects will be created when i > = 128 | i < - 128, and the created specified objects will be returned according to the value of i when i < 128 & & i > = - 128.
These may not be very clear. Let's take an example:
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); //true System.out.println(i3==i4); //false } }
At the back of the code, we can see that their execution results are different. Why? Look at our instructions above.
1. i1 and i2 will be automatically boxed and the valueOf function is executed. If their values are within the range (- 128128), they will get the same object SMALL_VALUES[228] in the SMALL_VALUES array. They refer to the same Integer object, so they must be equal.
2. i3 and i4 will also be automatically boxed and execute the valueOf function. Their value is greater than 128, so they will execute new Integer(200), that is, they will create two different objects respectively, so they must be different.
Let's take another example:
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); //false System.out.println(i3==i4); //false } }
Look at the above execution results. They are different from Integer. It's not surprising, because their valueOf implementations are different, and the results must be different. Why don't they be unified?
This is easy to understand. For integers, there are only 256 fixed values between (- 128128]), so in order to avoid creating objects many times, we have created an Integer array SMALL_VALUES with a size of 256 in advance. Therefore, if the value is within this range, we can directly return the objects we have created in advance.
However, for Double type, we can't do this because its number is infinite in this range. To sum up, the number of integer values in a range is limited, but floating-point numbers are not.
Therefore, the method in Double is very direct, which is to directly create an object, so the object created each time is different.
public static Double valueOf(double d) { return new Double(d); }
Let's make a classification:
Integer faction: the implementation of valueOf methods of integer, Short, Byte, Character and Long is similar.
Double faction: the implementation of the valueOf methods of double and Float is similar. Different objects are returned each time.
The Integer faction is summarized as follows:
Let's look at another situation:
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);//true System.out.println(i3==i4);//true } }
You can see that all returned are true, that is, they execute valueOf and return the same object.
public static Boolean valueOf(boolean b) { return b ? Boolean.TRUE : Boolean.FALSE; }
You can see that it does not create objects, because two objects have been created internally in advance, because there are only two cases. This is also to avoid creating too many objects repeatedly.
public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false);
Several situations have been introduced above, and other situations will be further discussed below.
Integer num1 = 400; int num2 = 400; System.out.println(num1 == num2); //true // Description num1 == num2 unpacked Integer num1 = 100; int num2 = 100; System.out.println(num1.equals(num2)); //true
Let's take a look at the source code of equals:
@Override public boolean equals(Object o) { return (o instanceof Integer) && (((Integer) o).value == value); }
We specify that equal compares the content itself, and we can also see that the parameter of equal is an Object object. We pass in an int type, so it will be boxed first and then compared. The reason why it returns true is that it compares the value value in the Object.
Integer num1 = 100; int num2 = 100; Long num3 = 200l; System.out.println(num1 + num2); //200 System.out.println(num3 == (num1 + num2)); //true System.out.println(num3.equals(num1 + num2)); //false
1. When a basic data type performs = =, +, -, *, / operations with the encapsulated class, the encapsulated class will be unpacked and the basic data type will be operated. 2. The reason why num3.equals(num1 + num2) is false is very simple. Let's explain it according to the code implementation:
@Override public boolean equals(Object o) { return (o instanceof Long) && (((Long) o).value == value); }
It must meet two conditions to be true:
1. Same type
2. Same content
The reason why false is returned above is that the types are different.
Integer num1 = 100; Ingeger num2 = 200; Long num3 = 300l; System.out.println(num3 == (num1 + num2)); //true
Let's decompile some of this class file: javap -c StringTest
You can see that during the operation, first unpack num3 (execute the longValue of num3 to get the value 300 with the basic type of long), then unpack num1 and mum2 (execute the intvalues of num1 and num2 to get the values 100 and 200 with the basic type of int respectively), and then perform relevant basic operations.
Let's test the basic type:
int num1 = 100; int num2 = 200; long mum3 = 300; System.out.println(num3 == (num1 + num2)); //true
This explains why true is returned at the top
Therefore, when both operands of the = = operator are references of wrapper type, it is to compare whether they point to the same object. If one of the operands is an expression (that is, it contains arithmetic operations), it is to compare a value (that is, it will trigger the process of automatic unpacking).
Trap 1:
Integer integer100=null; int int100=integer100;
These two lines of code are completely legal and can be compiled, but null pointer exceptions will be thrown at run time. Of course, integer100 is an object of Integer type, which can point to null. However, in the second line, integer100 will be unpacked, that is, intValue() will be executed on a null object Method, of course, will throw a null pointer exception. Therefore, when unpacking, you must pay special attention to whether the encapsulated class object is null.
summary
1. You need to know when it will cause packing and unpacking
2. Boxing operations will create objects. Frequent boxing operations will consume a lot of memory and affect performance. Therefore, boxing can be avoided as much as possible.
3. equals(Object o) because the parameter type in the original equals method is the encapsulation type and the passed in parameter type (a) is the original data type, it will be boxed automatically. On the contrary, it will be unpacked
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 unpacked or boxed automatically
Source: https://www.cnblogs.com/wang-yaz/p/8516151.html
Recent hot article recommendations:
1.1000 + Java interview questions and answers (2021 latest version)
2.Stop playing if/ else on the full screen. Try the strategy mode. It's really fragrant!!
3.what the fuck! What is the new syntax of xx ≠ null in Java?
4.Spring Boot 2.6 was officially released, a wave of new features..
5.Java development manual (Songshan version) is the latest release. Download it quickly!
Feel good, don't forget to like + forward!