In this article, the author will introduce to you a very important and interesting feature in Java, which is automatic boxing and unboxing, and interpret the principles of automatic boxing and unboxing from the source code. At the same time, this feature also leaves a trap. If developers do not pay attention, they will easily fall into this trap.
Autoboxing
definition
When writing Java programs, people often define an Integer object in the following ways:
Integer i=100;
From the above code, you can know that i is a reference of type Integer and 100 is the basic data type in Java (primitive data type). This method of directly passing a basic data type to its corresponding wrapper class is automatic boxing.
In jdk 1.5, automatic boxing was introduced for the first time. Before jdk 1.5, if you want to define an Integer object with a value of 100, you need to do this:
Integer i=new Integer (100);
principle
Let's make a breakpoint at the above code "Integer i=100;" and follow it.
Next, we can see that the program jumps to the valueOf(int i) method of the Integer class.
/** * Returns a <tt>Integer</tt> instance representing the specified * <tt>int</tt> value. * If a new <tt>Integer</tt> instance is not required, this method * should generally be used in preference to the constructor * {@link #Integer(int)}, as this method is likely to yield * significantly better space and time performance by caching * frequently requested values. * * @param i an <code>int</code> value. * @return a <tt>Integer</tt> instance representing <tt>i</tt>. * @since 1.5 */ public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) return IntegerCache.cache[i + 128]; else return new Integer(i); }In other words, packing is jdk that helps you complete the call to Integer.valueOf(100).
Unboxing
definition
Integer integer100=100;int int100=integer100;
From the above code, you can see that integer100 is a reference to type Integer, and int100 is a primitive data type of type Int. However, we can assign an Integer type object to a variable of its corresponding original data type. This is unboxing.
Unboxing is the opposite of packing. Boxing is a variable that assigns a primitive data type to the corresponding encapsulated class. Unboxing means assigning a variable of an encapsulated class to a variable of the corresponding original data type. The names of packing and unboxing are also quite appropriate.
principle
I believe everyone has guessed what jdk did for us during the unboxing process. Let's prove our conjecture through experiments.
Set a breakpoint on the second line of the above code, that is, set a breakpoint on "int int100=integer100;" and follow it.
We can see that the program jumps to Integer's intValue() method.
/** * Returns the value of this <code>Integer</code> as an * <code>int</code>. */ public int intValue() {return value; }That is, jdk helps us complete the call to the intValue() method. For the above experiment, it is to call the intValue() method of integer100 and assign its return value to int100.
Extended
Experiment 1
Integer integer400=400;int int400=400;System.out.println(integer400==int400);
In the third line of the above code, integer400 and int400 execute the == run. And these two are different types of variables. Are integer400 unboxing or int400 packing? What are the results of the operation?
== operation is to determine whether the addresses of two objects are equal or whether the values of the two basic data types are equal. Therefore, it is easy to infer that if integer400 is unboxed, it means that the values of the two basic types are compared, and the running result must be true at this time; if int400 is packed, it means that the addresses of the two objects are equal, and the running result must be false at this time. (As for why the author assigns them to 400, it is related to the traps that will be discussed later).
Our actual running result is true. So it was integer400 unboxing. The results of code tracking prove this.
Experiment 2
Integer integer100=100;int int100=100;System.out.println(integer100.equals(int100));
In the third line of the above code, the parameter of integer100's method equals is int100. We know that the parameters of the equals method are Object, not the basic data type, so here it must be int100 packed. The results of code tracking prove this.
In fact, if the parameter type in a method is the original data type and the parameter type passed in is its encapsulation class, it will be automatically unboxed; accordingly, if the parameter type in a method is the encapsulation type and the parameter type passed in is its original data type, it will be automatically boxed.
Experiment 3
Integer integer100 = 100;int int100 = 100;Long long200 = 200l;System.out.println(integer100 + int100);System.out.println(long200 == (integer100 + int100));System.out.println(long200.equals(integer100 + int100));
In the first experiment, we have learned that when a basic data type performs == operation with the encapsulation class, the encapsulation class will be unboxed. What if +, -, *, /? We can know in this experiment.
If + operation, the underlying data type will be boxed, then:
•In line 4, integer100+int100 will get an object o of type Integer and value 200, and execute the toString() method of this object and output "200";
•In line 5, integer100+int100 will get an object o of type Integer and value of 200. The == operation compares this object with a long200 object. Obviously, false will be output;
•In line 6, integer100+int100 will get an object o of type Integer and value 200. Long's equals method compares long200 with o, because both are encapsulated classes of different types, so the output is false;
If + operation, the encapsulation class will be unboxed, then:
•In line 4, integer100+int100 will get a basic data type b of type int and value 200, then box b to obtain o, execute the toString() method of this object, and output "200";
•In line 5, integer100+int100 will get a basic data type b1 of type int and value 200. The == operation unboxes long200 to obtain b2. Obviously b1==b2, and outputs true;
•In line 6, integer100+int100 will get a basic data type b of type int and value 200. Long's equals method boxs b, but the boxing results in object o of type Integer, because o and long200 are objects of different types, so the output is false;
The result of the program running is:
200
true
false
Therefore, the second speculation is correct, that is, the encapsulation class will be unboxed during the + operation.
trap
Trap 1
Integer integer100=null;
int int100=integer100;
These two lines of code are completely legal and can be compiled completely, but when run, a null pointer exception will be thrown. Among them, integer100 is an object of type Integer, which of course can point to null. But in the second line, integer100 will be unboxed, that is, the intValue() method will be executed on a null object, and of course, a null pointer exception will be thrown. Therefore, when unboxing, you must pay special attention to whether the encapsulated class object is null.
Trap 2
Integer i1=100;
Integer i2=100;
Integer i3=300;
Integer i4=300;
System.out.println(i1==i2);
System.out.println(i3==i4);
Because i1, i2, i3, and i4 are all Integer types, we think that the running results should be false. However, the real running result is "System.out.println(i1==i2);" which is true, but "System.out.println(i3==i4);" which is false. This means that the references of the two Integer types, i1 and i2, point to the same object, while i3 and i4, point to different objects. Why? Aren't they all called the Integer.valueOf(int i) method?
Let's take a look at the Integer.valueOf(int i) method again.
/** * Returns a <tt>Integer</tt> instance representing the specified * <tt>int</tt> value. * If a new <tt>Integer</tt> instance is not required, this method * should generally be used in preference to the constructor * {@link #Integer(int)}, as this method is likely to yield * significantly better space and time performance by caching * frequently requested values. * * @param i an <code>int</code> value. * @return a <tt>Integer</tt> instance representing <tt>i</tt>. * @since 1.5 */ public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) return IntegerCache.cache[i + 128]; else return new Integer(i); }We can see that when i>=-128 and i<=IntegerCache.high, the IntegerCache.cache[i + 128] is returned directly. Among them, IntegerCache is an internal static class of Integer, and its original code is as follows:
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() {} }We can clearly see that IntegerCache has a static member variable cache, which is an array with 256 elements. The cache is also initialized in IntegerCache, that is, the i-th element is an Integer object with a value of i-128. -128 to 127 are the most commonly used Integer objects, and this approach also greatly improves performance. It is also because of this that "Integeri1=100;Integer i2=100;", i1 and i2 get the same object.
Comparing the second experiment in the extension, we learned that when the encapsulation class is running == with the basic type, the encapsulation class will unbox, and the unboxing result is compared with the basic type; while when the two encapsulation classes are running == with the other objects, they compare the addresses of the two objects, that is, to determine whether the two references point to the same object.
The above article briefly discusses Java automatic packing and unboxing and its traps is all the content I share with you. I hope it can give you a reference and I hope you can support Wulin.com more.