1. Introduction
Java is a strongly typed language, which means you must declare a type for each variable. In Java, there are eight basic data types, and each basic data type contains a corresponding wrapper type. The corresponding relationship is shown in the following table:
Basic types of | Packing type |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
The basic type and the wrapper type seem to overlap in functionality and are a bit redundant. In fact, they have their own advantages and disadvantages and application scenarios.
1.1 Basic Types
“Advantages”
- Saves memory by not creating extra object space in the heap.
- Efficient access, no additional addressing.
- Operating efficiency is higher.
“Defect”
- NULL is not allowed and must have a value.
- Does not conform to the characteristics of object-oriented programming.
- Generics are not supported.
- Not allowed as a “lock” object (no object header).
1.2 Packing Type
“Advantages”
- Conforms to the object oriented programming characteristic.
- Support generics.
- NULL is allowed.
- Enriched the basic types of operations.
- Support generics.
“Defect”
- More memory intensive, it’s a complete object.
- Access needs to be addressed against the Reference Reference.
To sum up, it can be found that the advantages and disadvantages of the basic type and the packaging type are complementary, which also shows that the existence of the two is not contradictory, and it is better to choose the appropriate type in different application scenarios.
2. Automatic unpacking/packing
Both basic and wrapper types have their advantages, but in order to improve developer coding efficiency and code readability, Java’s “automatic unpacking/packing” feature weakens the distinction between basic and wrapper types. Most of the time, you can use a mix of the two.
What is “automatic unpacking/packing”? In simple terms, you can assign a wrapper object directly to a variable of a primitive type. You can assign a primitive type directly to a variable of a wrapper type. You can even assign a wrapper type directly to a variable of a primitive type.
void function(a) {
Integer a = new Integer(0);
int b = a;
Integer c = b;
int d = a + b;
}
Copy the code
Isn’t it amazing that Java automatically converts between basic and wrapper types? How did you do that? We’ll talk about that later.
The following example shows how jumbled the code would be without automatic unboxing/boxing.
// Automatic unpacking/packing is not supported
public Integer add(Integer a, Integer b) {
int sum = a.intValue() + b.intValue();
return Integer.valueOf(sum);
}
// Support automatic unpacking/packing
public Integer add(Integer a, Integer b) {
return a + b;
}
Copy the code
Automatic unpacking/packing works very well, but if the developer is inexperienced, he or she will step into the pit. The following code example:
public static void main(String[] args) {
print(null);
}
public static void print(Boolean isPrint) {
if (isPrint) {
System.out.println("Output a paragraph..."); }}Copy the code
This code compiled without any problems, but when run, it emits a NullPointerException. Print () takes a Boolean parameter and allows it to accept null, but instead of finding null, it makes a Boolean judgment, where “smart” Java automatically unboxes the Boolean and converts it to a Boolean, resulting in a null pointer. Therefore, when unpacking, in order to avoid null pointer, must be empty first.
3. Decryption automatic unpacking/packing
Now that you know what auto-unpacking/stuffing is all about, let’s break it down.
The.Java files we write are source code files that humans can read, but machines can’t. In order for the machine to understand and execute, it needs to be compiled by a Javac program, and the compiled.class file can be read, translated into native machine code and executed by the JVM. That’s later.
The automatic unpacking/packing step is implemented when the Javac program is compiled.
Let’s take the following example to see what the compiled file looks like and how the machine executes it.
public class Demo {
public Integer add(Integer a, Integer b) {
returna + b; }}Copy the code
Javac demo. Java is compiled into a bytecode file, and then the javAP -verbose Demo is disassembled to get the actual JVM instructions.
I just post the instruction set for the add() method, as follows:
public java.lang.Integer add(java.lang.Integer, java.lang.Integer); descriptor: (Ljava/lang/Integer; Ljava/lang/Integer;) Ljava/lang/Integer; flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=3
0: aload_1
1: invokevirtual #2 // Method java/lang/Integer.intValue:()I
4: aload_2
5: invokevirtual #2 // Method java/lang/Integer.intValue:()I
8: iadd
9: invokestatic #3 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
12: areturn
LineNumberTable:
line 11: 0
Copy the code
Look not to understand? Just go to Google “JVM instruction set” and I’ll explain what each instruction is doing.
instruction | instructions |
---|---|
aload_1 | Push the second reference type local variable to the top of the stack, i.e. the variable A to the top. |
invokevirtual | Execute instance method: integro.intValue (), that is, a.ntvalue () is called |
aload_2 | Push the third reference type local variable to the top of the stack, i.e. the variable B to the top. |
invokevirtual | Execute the instance method: integ.intValue (), that is, b.ntValue () is called. |
iadd | The a+b operation is performed by adding two int values at the top of the stack and pushing the result to the top. |
invokestatic | Call the static method: integer.valueof (), which encapsulates the result of the addition as a wrapper type. |
areturn | Returns an object reference from the current method, that is, returns the wrapper type result. |
Is that clear? Although we write the source code does not do type conversion, but compiled the program, automatically help us to do the processing oh. So the seemingly magical “unboxing/bobbing” isn’t a big deal, except that the compiler does the casting for us.
For example, when int and Integer are converted, the integer.valueof () and integer.intValue () methods are called.
Therefore, the above code is equivalent to the following code:
public class Demo {
public Integer add(Integer a, Integer b) {
returnInteger.valueOf(a.intValue() + b.intValue()); }}Copy the code
Again compile, the instruction set is exactly the same, I will not paste, you can try it yourself ha ~ ~
4. To summarize
The existence of a basic type and a package type is not contradictory. Each has its advantages and disadvantages complement each other. In order to make the code easier to write and more readable, Java’s “automatic unboxing/bobbing” feature weakens the distinction and makes it easier to use. The seemingly magical “automatic unboxing/boxing” feature is not so advanced as to add valueOf() and xxxValue() methods at Javac compile time to complete the type conversion.
As a final note, calling xxxValue() when a NULL object is unboxed results in a NULL pointer exception