Java tool class -- wrapper class
As we all know, the JDK actually provides us with many ready-made classes that have been written by many Java developers. In fact, they can be understood as tool classes, such as our common collection classes, date related classes, math related classes, etc. with these tool classes, you will find that it can help you save time to a great extent and realize your needs conveniently. Of course, without these packages, you can meet your needs, but you need time. Today we mainly learn about packaging.
1, Introduction to packaging
1. Why do I need packaging?
We know that the Java language is an object-oriented programming language, but the basic data types in Java are not object-oriented, but we often need to convert the basic data types into objects in actual use to facilitate operations. For example, in the operation of collections, at this time, we need to convert the basic type data into objects, so there is a wrapper class.
2. What is the packaging category?
Packaging classes, as the name suggests, are classes that are packaged. What are they packaged? Obviously, here are classes that package basic types. The function of a wrapper class is to convert a basic type into an object and treat the basic type as an object.
In Java, we know that there are 8 basic data types, so there are also 8 corresponding wrapper classes. The wrapper class is the initial capitalization of the name of the basic type. The exceptions are Integer and Character, which display their full names, as shown in the following table:
Basic data type | Corresponding packaging class |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
2, Inheritance relationship of wrapper class
By reading the official API documentation of Java8 or looking at the source code, we can learn that the inheritance relationships of the eight wrapper classes are as follows:
From the above inheritance diagram, we can actually remember that in the wrapper class, six numbers related items are inherited from the Number class, while the other two items that are not related to numbers are inherited from the Object class by default. By looking at the official API documentation, we can also see that these 8 wrapper classes implement the serializable and comparable interfaces. For example, the Integer class in the following figure
public final class Integer extends Number implements Comparable<Integer> {}
3, Usage of packaging class (basic operation)
Next, I will talk about the Integer wrapper class, and so on. The usage and operation are the same, but the name is different.
1. Construction method of packaging class
All the 8 wrapper classes have constructors with their corresponding type parameters. Among the 8 wrapper classes, there are constructor overloads in addition to Character, and the parameters are of String type.
Integer one = new Integer(666); Integer two = new Integer("666");
2. Automatic disassembly and assembly box for packaging
Before we know about automatic unpacking, we have to know what is unpacking and packing. In fact, the disassembly and assembly of boxes mainly deal with the mutual conversion between basic types and packaging types.
-
Boxing: the process of converting a primitive type to a wrapper type is called boxing.
-
Unpacking: the process of converting a package type to a basic type is called unpacking.
In fact, before JDK1.5, there was no automatic box disassembly and assembly. Developers should manually unpack and assemble boxes:
//Manual boxing, that is, converting basic type 10 to reference type Integer integer = new Integer(10); //perhaps Integer integer1 = Integer.valueOf(10); //Manual unpacking, that is, converting reference types to basic types int num = integer.intValue();
After JDK1.5, in order to reduce the work of developers, the functions of automatic packing and unpacking are provided. It realizes automatic unpacking and automatic packing, as shown in the following code:
//Automatic packing Integer one = 1; //Automatic unpacking int two = one + 10;
In fact, the above two methods are essentially the same, except that one is implemented automatically and the other is implemented manually. As for how to realize the automatic disassembly and assembly box, I will not do in-depth research here.
4, Caching mechanism of wrapper classes
Let's first look at the following code, example 1:
public static void main(String[] args) { Integer i1 = 100; Integer i2 = 100; Integer i3 = new Integer(100); Integer i4 = new Integer(100); System.out.println(i1 == i2);//true System.out.println(i1 == i3);//false System.out.println(i3 == i4);//false System.out.println(i1.equals(i2));//true System.out.println(i1.equals(i3));//true System.out.println(i3.equals(i4));//true }
When we modify the value to 200, example 2:
public static void main(String[] args) { Integer i1 = 200; Integer i2 = 200; Integer i3 = new Integer(200); Integer i4 = new Integer(200); System.out.println(i1 == i2);//false System.out.println(i1 == i3);//false System.out.println(i3 == i4);//false System.out.println(i1.equals(i2));//true System.out.println(i1.equals(i3));//true System.out.println(i3.equals(i4));//true }
Through the codes at the two ends above, we found that the value was modified, and the execution result of the code in line 5 was changed. Why? First, we need to make it clear that lines 1 and 2 actually implement the process of automatic boxing, that is, integer Valueof method. Secondly, the address is compared, while equals compares the value (eauals here is rewritten, so the specific value is compared). Therefore, there is no doubt about the execution result of the last five lines of code. Since the address is compared, why is the code in line 5 of example 1 true? This requires us to understand the caching mechanism of the wrapper class.
In fact, looking at the source code of the Integer class, we can find that there is a private static internal class in line 780, as follows:
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; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } 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; } private IntegerCache() {} }
As we know, the static internal class is loaded when the whole Integer is loaded. The above code initializes an array of Integer type called cache. The value range is [-128, 127]. The function of the caching mechanism is to instantiate the wrapper class object of the corresponding range value in advance. As long as the object in the cache range is created, the instantiated object will be used. Thus, it can avoid creating multiple identical wrapper class objects repeatedly and improve the efficiency. If the object range we use is within [-128, 127], we can directly go to the static area to find the corresponding object. If the object range exceeds this range, it will help us create a new Integer object. In fact, the following source code means this:
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
Therefore, in the code of example 1, I1 and I2 are 100, and the range of values is [-128, 127], so the static area is directly searched, so I1 and I2 point to the same address, so i1==i2; In the code of example 2, I1 and I2 are 200, and the range of values is not [-128, 127], so a new object is created and placed in the heap memory, and each object points to different addresses, so the addresses are different. Naturally, I1 is not equal to I2.
By analyzing the source code, we can find that only the double and float auto boxing codes do not use caching, and each time they are new objects. The other six basic types use caching strategies.
The cache policy is used because these cached objects are frequently used (such as characters and numbers between -128 and 127), so as to prevent the creation of an object instance every time auto boxing.
5, Difference between package class and basic data type
- Different default values
The default value of the wrapper class is null, while the basic data type is the corresponding default value (for example, the default value of integer type is 0, and the default value of floating point type is 0.0)
- Different storage areas
The basic data type is to save the value in the stack memory, and the wrapper class is to put the object in the heap, and then call them through the reference of the object
- Different delivery methods
In the variable space of the basic data type, values are stored and transferred. One change and the other change. While the packaging class belongs to the reference data type. In the variable space, addresses (references) are stored and references are transferred. One change and the other change.
5, Summary
The The above is my personal understanding of Java wrapper classes. In fact, there is a better way to learn these tool classes by looking at the official documents (API official document address: https://docs.oracle.com/javase/8/docs/api/)
Official account: Liangxu Linux
