Analyze the boxing and unboxing in Java from the perspective of bytecode

1. Basic introduction of unboxing and packing

Boxing and unboxing are two useful syntactic sugars provided in Java.

Boxing refers to the automatic conversion of a basic data type to its wrapper type. Such as the conversion of int to Integer.

Unboxing refers to converting the wrapper type to the corresponding basic data type. Such as the conversion of Integer to int.

The following is an example:

Integer num1 = 1000;
int num2 = num1;

Among them, num1 is an object of type Integer, and the assignment operation to it here is a boxing process.

num2 is a variable of the basic type int, and assigning a value to it with num1 is an unboxing process.

2. Bytecode implementation of unboxing and boxing

Let's take a look at how boxing and unboxing are implemented from the perspective of bytecode.

So how to get the bytecode of Java code? In fact, the class file we get after compiling the Java source code with javac is its bytecode file.

But this class file exists in binary form and cannot be read directly. So we need another command javap to help us parse the class file into a readable form .

We save the following code in the test.java file (category, main method, etc. are omitted here):

Integer num1 = 1000;
int num2 = num1;

Use of javap command
Then use javac to compile, and then use javap -v to decompile. With javap plus the -v parameter, you can see more comprehensive information.

javac test.java
javap -v test

After using javap to decompile , we can get the following results:

         0: sipush        1000
         3: invokestatic  #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         6: astore_1
         7: aload_1
         8: invokevirtual #3// Method java/lang/Integer.intValue:()I
        11: istore_2

The decompilation result here contains 6 bytecode instructions. If you understand these instructions, you will also understand the principle of a common unboxing and boxing implementation.

Since these instructions correspond to various operations on the stack frame, we first review the concept of the stack frame.

Stack frame review

I believe everyone is familiar with the Java virtual machine stack in the Java runtime data area .

The process of each Java method from invocation to completion of execution corresponds to the process of pushing a stack frame into and out of the virtual machine stack.

The execution process of the method is to perform various operations on the stack frame.

Here we mainly focus on the operand stack and local variable table in the stack frame.
Java stack frame

Instruction execution analysis

Below we analyze in detail the execution process of the above 6 instructions.

Java code

Integer num1 = 1000;
int num2 = num1;

Corresponding bytecode

         0: sipush        1000
         3: invokestatic  #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         6: astore_1
         7: aload_1
         8: invokevirtual #3// Method java/lang/Integer.intValue:()I
        11: istore_2

The first sentence: sipush 1000

Sipush is a push operation, which means to put the short type number into the stack frame. The stack frame after executing this sentence is as follows:

sipush 1000
You can see that the number 1000 is placed in the operand stack.

Second sentence: invokestatic #2

This sentence is to call a static method.

So which method is specifically called?

You can see that there is a #2 parameter behind. This #2 can be understood as an index of the constant pool.

In addition to outputting the bytecode corresponding to the above code, we used the javap -v command. Another important part is the constant pool.

The constant pool of this decompilation is shown in the following figure:
Insert picture description here
You can see the location of index #2, and it stores a method descriptor. In fact, you can directly see the following comments. This method is the Integer.valueOf method.

I won’t say more about the constant pool here, as everyone knows it for the time being.

Back to our topic. We now know that the instruction invokestatic #2 calls the Integer.valueOf method, so who is the input parameter?

Remember what the last instruction did?

Correct. Put the number 1000 on the top of the operand stack. The number 1000 on the top of the stack is actually the input parameter of Integer.valueOf.

The return value of Integer.valueOf is an Integer object. After executing this instruction, 1000 is popped from the stack, and the result Integer object is pushed onto the stack. This Integer object is num1 in our Java code.

At this time, the stack frame is as follows: The
Insert picture description here
third sentence: astore_1

This sentence means popping the top element of the operand stack and placing it in the position where the subscript of the local variable table is 1.

The results after execution are as follows:

Insert picture description here

When this sentence is executed, Integer num1 = 1000 in the Java code, even if the execution is finished.

Boxing conclusion

The first three bytecodes complete the boxing operation. Through the above analysis, we know that the boxing of integers is achieved by calling the Integer.valueOf method.

It is similar for other data types.

The last three sentences of bytecode correspond to the process of int num2 = num1.

The fourth sentence: aload_1
means to push the element whose position is 1 in the local variable table into the operand stack.

The result of this sentence is as follows.

aload_1
The fifth sentence: invokevirtual #3

Similar to the second sentence of invokestatic, this sentence is also a method call execution.

It's just an example method called here.

Participate in the constant pool situation given in the second sentence analysis, the method called here is the intValue method of Integer.

The operand is the Integer object pushed onto the stack in the previous step.

The results after execution are as follows:

Insert picture description here

Sixth sentence: istore_2

Store the elements of the operand stack in the second position of the local variable table.

Insert picture description here
At this point, the execution is complete int num2 = num1

Finally, num1 and num2 are stored in the 1 and 2 positions of the local variable table.

Unboxing conclusion

Through the analysis of the last three bytecodes, we know that the unboxing of the Integer type is implemented using Integer.intValue.

The same is true for other wrapper types.

3. Summary of this article

This article introduces the meaning of boxing and unboxing. Then obtained the bytecode implementation of the assembling and unboxing through the javap command. And analyze these byte codes sentence by sentence.

Finally, for the integer type, the boxing is to use the Integer.valueOf method, and the unboxing is to use the Integer.intValue method to achieve the conclusion.


If this article is helpful to you, please pay attention to my original WeChat public account "Java Technology Station" to receive more of my articles as soon as possible
Insert picture description here

Guess you like

Origin blog.csdn.net/vxzhg/article/details/103830715