Six years ago, when I returned to Luoyang from Suzhou, I put in many resumes and interviewed many interviewers with a mentality of returnees, but only two or three satisfied me. One of them, Lao Ma, is still in my mobile address book. He threw an interview question at me: tell me the difference between basic type and packaging type.
I was 23 years old at that time and had N years of experience in Java programming (N < 4). I thought all the interview questions could be answered smoothly. Unexpectedly, I was "difficult". There were also technical experts in the desert of the Internet in Luoyang. Looking back now, a shame glow came over my face: mainly because I was too dished. Anyway, it's time to write an article to analyze the differences between basic types and packaging types.
Each basic type of Java corresponds to a packaging type, such as Integer for int and Double for double. There are four main differences between basic types and packaging types.
01. Packaging type may be null, but basic type may not.
Don't underestimate this difference, it allows wrapping types to be applied in POJO, but not basic types.
What is POJO? Here's a little explanation.
The full English name of POJO is Plain Ordinary Java Object, which translates into a simple, irregular Java object with only attribute fields and setter and getter methods, as shown below.
class Writer { private Integer age; private String name; public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Similar to POJO, there are data transfer object DTO (Data Transfer Object), view object VO (View Object, which encapsulates data from a page), persistent object PO (Persistant Object, which can be viewed as a Java object mapped to a table in a database).
Why do POJO attributes have to be wrapped?
The Alibaba Java Development Manual has detailed instructions. Let's read them out loud (Ready, Get Up).
The result of a database query can be null, and if you use the base type, you throw a NullPointerException exception to automatically unpack (convert the package type to the base type, for example, convert an Integer object to an int value).
02. Packaging types can be used for generics, but basic types cannot
Generics cannot use base types because they compile errors when used.
List<int> list = new ArrayList<>(); // Prompt Syntax error, insert "Dimensions" to complete
ReferenceType List<Integer> list = new ArrayList<>();
Why? Because generics do type erasing at compilation time, only the original type is retained, and the original type can only be an Object class and its subclasses - the basic type is a special case.
03. Basic types are more efficient than packaging types
The base type stores specific values directly in the stack, while the wrapper type stores references in the stack.
Obviously, the packaging type takes up more memory space than the basic type. If there are no basic types, it would be cumbersome to use a new packaging type for data such as numeric values, which are often used.
03. The values of the two packaging types may be the same, but not the same
Two packaging types can have the same value, but not the same value - what do you mean by that? Just look at the code and it's clear.
Integer chenmo = new Integer(10); Integer wanger = new Integer(10); System.out.println(chenmo == wanger); // false System.out.println(chenmo.equals(wanger )); // true
When two packaging types are judged by using'', they are judged to point to the same address. Two variables, chenmo and wanger, use the new keyword, causing them to output false when''.
The output of chenmo.equals(wanger) is true because the equals method compares whether the two int s are equal. The source code is as follows.
private final int value; public int intValue() { return value; } public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
Look, although both chenmo and wanger have values of 10, they are not equal. In other words, when the'=='operator is applied to a package type comparison, the result is likely to be different than expected.
04. Automatic packing and unloading
Now that you have the basic types and packaging types, there are times when you have to convert between them. The process of converting a basic type to a packaging type is called boxing. Conversely, the process of converting a packaging type to a basic type is called unboxing.
Prior to Java SE5, developers had to manually load and unload boxes, such as:
Integer chenmo = new Integer(10); // Manual packing int wanger = chenmo.intValue(); // Manual Unboxing
Java SE5 provides automatic boxing and unboxing to reduce the work of developers.
Integer chenmo = 10; // Automatic packing int wanger = chenmo; // Auto-unboxing
The result of decompiling the above code with JAD is as follows:
Integer chenmo = Integer.valueOf(10); int wanger = chenmo.intValue();
That is, automatic packing is done through Integer.valueOf(); Automatic unboxing is done through Integer.intValue(). After understanding the principle, let's take a look at the interview question that Lao Ma gave me that year.
// 1) Basic Types and Packaging Types int a = 100; Integer b = 100; System.out.println(a == b); // 2) Two packing types Integer c = 100; Integer d = 100; System.out.println(c == d); // 3) c = 200; d = 200; System.out.println(c == d);
What is the answer? Did you raise your hand to answer? A little safflower is rewarded for answering correctly.
The first section of code, the basic type and the packaging type are==compared, then b will be automatically unpacked, directly compared with a value, so the result is true.
In the second section of the code, both packaging types are assigned a value of 100, which will automatically be boxed. What is the result of ==?
Our previous conclusion was that when the'=='operator was applied to a comparison of packaging types, the results would most likely not match what was expected. So the result is false? But this time it turned out to be true, isn't it surprising?
In the third section of the code, the two packaging types are re-assigned a value of 200, and the auto-packing still takes place. What is the result of ==then?
Having suffered the loss of the second code, is there any doubt about life, is it true or false this time? Throw a coin, haha. Let me tell you first, false.
Why? Why? Why?
At this point, you must use the killer's mace - analyze the source code.
We already know that automatic packing is done through Integer.valueOf(), so let's see the source code for this method.
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
Is IntegerCache kidding? Bingo!
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); h = Math.min(i, Integer.MAX_VALUE - (-low) -1); high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } }
Take a glance at this code and you'll see it all. - Numbers between 128 and 127 are taken from IntegerCache and compared, so the result from the second code (100 is in this range) is true, and the result from the third code (200 is not in this range, so new comes out with two Integer objects) is false.
After reviewing the above analysis, I want you to keep in mind that when automatic boxing is required, if the number is between -128 and 127, the object in the cache will be used directly instead of re-creating it.
Auto-loading and unpacking is a good feature, which saves our developers'energy, but it can also cause some troubles, such as the following code, which has poor performance.
long t1 = System.currentTimeMillis(); Long sum = 0L; for (int i = 0; i < Integer.MAX_VALUE;i++) { sum += i; } long t2 = System.currentTimeMillis(); System.out.println(t2-t1);
sum += i did a lot of unpacking because it was declared as packing type Long instead of basic type long (sum first unpacked and i added, then boxed and assigned to sum), which took 2986 milliseconds for the code to complete. If you change the sum to the basic type long, it will only take 554 milliseconds, which is not an equal magnitude at all.
05, Last
Thank you for your reading. The originality is not easy. If you like it, you can praise it. This will be my strongest writing power. If you find the article helpful and interesting, pay attention to me.