1. Basic introduction of unpacking and packing

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

Boxing is the automatic conversion of a base data type to its wrapper type. Such as the conversion from int to Integer.

Unpacking refers to converting the wrapper type to the corresponding base data type. Such as Integer to int conversion.

Here’s an example:

Integer num1 = 1000;
int num2 = num1;
Copy the code

Num1 is an object of type Integer, and its assignment is a boxing procedure.

Num2 is a variable of basic int, and assigning it to num1 is an unboxing process.

Two. Unpacking and packing bytecode implementation

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

So how do you get the bytecode of Java code? In fact, the class file we get after compiling Java source code using Javac is its bytecode file.

But the 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 (omits the class, main method, and so on) :

Integer num1 = 1000;
int num2 = num1;
Copy the code

The javap command is then compiled with javac and decompiled with javap -v. The javap plus the -v argument gives you more comprehensive information.

javac test.java
javap -v test
Copy the code

Using javap decompilation, we get the following result:

         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
Copy the code

The result of the decompilation here consists of six bytecode instructions, and once you understand these instructions, you can see how a normal unpacking and boxing process works.

Since these instructions correspond to various operations on a stack frame, let’s first review the concept of a stack frame.

The stack frame review

You are familiar with the Java virtual machine stack in the Java runtime data area.

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

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

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

Instruction execution analysis

Let’s analyze the execution process of the above six instructions in detail.

Java code

Integer num1 = 1000;
int num2 = num1;
Copy the code

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
Copy the code

Sipush 1000

Sipush is a push operation that puts short numbers into a stack frame. After executing this statement, the stack frame looks like this:

Invokestatic #2

Call a static method.

So which method is called?

You can see that there is also a #2 argument behind it. This #2 can be thought of as an index to the constant pool.

We use javap -v command in addition to output the above code corresponding bytecode. Another important part is the constant pool.

The constant pool for this decompilation is shown below:

I’m not going to say much more about constant pools, but you know that for now.

Back to our subject. We now know that invokestatic #2 invokes integer.valueof, so who is the input parameter?

Do you remember what the last order did?

right You put the number 1000 at the top of the operand stack. The number 1000 at the top of the stack is actually an input parameter to Integer.valueof.

The return valueOf integer. valueOf is an Integer object. After executing this instruction, 1000 is pushed off the stack and the resulting Integer object is pushed onto the stack. This Integer object is num1 in our Java code.

In this case, the stack frame is as follows:

AstORE_1

Pop the top element of the operand stack into the local variable table at subscript 1.

The result is as follows:

Integer num1 = 1000 in the Java code.

Conclusion using the

The first three bytecode sentences complete the packing operation. From the above analysis, we know that Integer boxing is done by calling integer.valueof.

The same is true for all other data types.

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

Aload_1 pushes the element at position 1 onto the operand stack.

The result of this sentence is as follows.

Invokevirtual #3

Similar to the second invokestatic sentence, this is the invocation of the method.

It’s just that a sample method is called.

Int int int int int int int int int int int int

Operands are the Integer objects that were pushed at the last step.

The result is as follows:

istore_2

Stores the operand stack element to the second location in the local variable table.

Finally, num1 and NUM2 are stored in positions 1 and 2 of the local variable scale.

Split open a case to the conclusion

Integer unpacking is implemented using integer.intValue.

The same is true for other wrapper types.

3. Summary of this paper

This paper introduces the meaning of packing and unpacking. Then get the bytecode implementation of packing and unpacking through javap command. And analyzed the bytecode sentence by sentence.

Finally, it is concluded that integer. valueOf is used for packing and integer. intValue is used for unpacking for Integer types.


If this article is helpful to you, please follow my original wechat official account “Java Technology Station” to receive more articles from me as soon as possible