Thinking logic of computer programs (26) and thinking 26
Packaging
Java has eight basic types, each of which has a corresponding packaging class.
What is the packaging class? It is a class that contains an instance variable and stores the value of the corresponding basic type. This class generally has some static methods, static variables, and instance methods to facilitate data operations.
In Java, the basic types and corresponding packaging classes are shown in the following table:
Basic Type |
Packaging |
Boolean
|
Boolean |
Byte
|
Byte |
Short
|
Short |
Int
|
Integer |
Long |
Long |
Float |
Float |
Double |
Double |
Char |
Character |
The packaging class is also easy to remember. Besides Integer and Character, the names of other classes are basically the same as the basic types, but only the first letter is capitalized.
What is the purpose of packaging? Many Java code (such as the collection class introduced in subsequent articles) can only operate on objects. to operate on basic types, you need to use the corresponding packaging class. In addition, the packaging class provides many useful methods, data operations are convenient.
The basic usage of the packaging class is relatively simple, but we will not only introduce its basic usage, but also introduce some of the less commonly used functions and analyze its implementation code, there are many contents. We will introduce them in three sections. This section describes the basic usage and commonalities of each packaging class. In the next two sections, we will further introduce advanced functions and analyze the implementation code.
Let's introduce it step by step.
Basic Types and packages
Let's first look at how the basic types and their packaging classes are converted. Let's look at the Code:
Boolean
boolean b1 = false;Boolean bObj = Boolean.valueOf(b1);boolean b2 = bObj.booleanValue();
Byte
byte b1 = 123;Byte byteObj = Byte.valueOf(b1);byte b2 = byteObj.byteValue();
Short
short s1 = 12345;Short sObj = Short.valueOf(s1);short s2 = sObj.shortValue();
Integer
int i1 = 12345;Integer iObj = Integer.valueOf(i1);int i2 = iObj.intValue();
Long
long l1 = 12345;Long lObj = Long.valueOf(l1);long l2 = lObj.longValue();
Float
float f1 = 123.45f;Float fObj = Float.valueOf(f1);float f2 = fObj.floatValue();
Double
double d1 = 123.45;Double dObj = Double.valueOf(d1);double d2 = dObj.doubleValue();
Character
char c1 = 'A';Character cObj = Character.valueOf(c1);char c2 = cObj.charValue();
These code structures are similar. Each packaging class has a static method valueOf (), which accepts the basic type, returns the reference type, and also has an instance method xxxValue () returns the corresponding basic type.
The process of converting a basic type to a packaging class is generally referred to as "Packing", while the process of converting a packaging type to a basic type is called "unpacking ". Since Java 1.5 and later introduces the automatic packing and unpacking technology, you can directly assign the basic type to the reference type, or vice versa, as shown in the following code:
Integer a = 100;int b = a;
Automatic packing/unpacking is the capability provided by the Java compiler. behind it, it will be replaced with the corresponding valueOf ()/xxxValue (). For example, the above Code will be replaced by the Java compiler:
Integer a = Integer.valueOf(100);int b = a.intValue();
Each packaging class also has a constructor, which can be created through new, for example:
Integer a = new Integer (100); Boolean B = new Boolean (true); Double d = new Double (12.345); Character c = new Character ('mar ');
So should we use the static valueOf method or new? ValueOf is generally recommended. New creates a new object each time, and other packaging classes except Float and Double will cache packaging class objects, reducing the number of times you need to create objects, saving space and improving performance, we will analyze the specific code in the future.
Override Object Method
All packaging classes override the following methods of the Object class:
boolean equals(Object obj)int hashCode()String toString()
Let's look at it one by one.
Equals
Equals is used to determine whether the current Object and the Object passed in by parameters are the same. The default Implementation of the Object class is the Compare address. For two variables, only when these two variables point to the same Object, equals returns true. It returns the same result as the comparison operator (=.
However, equals should reflect the logical equality between objects, so this default implementation is generally not suitable, and subclass needs to override this implementation. All packaging classes override this implementation. Actually, the basic type value of its packaging is used. For example, for the Long class, the equals method code is:
public boolean equals(Object obj) { if (obj instanceof Long) { return value == ((Long)obj).longValue(); } return false;}
For Float, the implementation code is:
public boolean equals(Object obj) { return (obj instanceof Float) && (floatToIntBits(((Float)obj).value) == floatToIntBits(value));}
Float has a static method floatToIntBits (), which treats the binary representation of float as an int. It should be noted that equals returns true only when the binary values of two float values are identical. In section 5th, we mentioned that decimal computation is not accurate, and the computation results are the same in terms of mathematics, but the computation results may be different. For example, let's look at the following code:
Float f1 = 0.01f;Float f2 = 0.1f*0.1f;System.out.println(f1.equals(f2));System.out.println(Float.floatToIntBits(f1));System.out.println(Float.floatToIntBits(f2));
Output:
false10089817701008981771
That is, the two floating point numbers are different, and the binary values are different as integers. The difference is 1.
The equals Method of Double is similar to Float. It has a static method doubleToLongBits, which treats the binary representation of double as long and then compares it by long.
HashCode
HashCode returns the hash value of an object. The hash value is a number of int type values, which are derived from the unaltered property ing of the object. It is used to quickly distinguish and group objects. The hash value of an object cannot be changed. The hash value of the same object must be the same. The hash values of different objects should be different, but this is not necessary. Different objects may have the same hash value.
For example, hashCode can be the birthdate of a student in a class, and the birthdate is the same. the birthdays of different students are generally different and the distribution is even, it doesn't matter if you have the same birthday.
The hashCode and equals methods are closely related. For two objects, if the equals method returns true, the hashCode must be the same. Otherwise, it is not required. When equal returns false, the hashCode can be the same or different, but it should be as different as possible. The default Implementation of hashCode is generally to convert the object's memory address to an integer. When the subclass overrides equals, hashCode must also be overwritten. The reason for this rule is that many classes in Java APIs depend on this behavior, especially some classes in the set.
The hashCode is overwritten in the packaging class. hashCode is calculated based on the basic type value of the packaging. For Byte, Short, Integer, Character, hashCode is its internal value, and the code is:
public int hashCode() { return (int)value;}
For Boolean, The hashCode code is:
public int hashCode() { return value ? 1231 : 1237;}
Two different numbers are returned based on the base class type value. Why are these two values selected? They are prime numbers, that is, they can only be divided by one and themselves. We will discuss later that prime numbers are good, but there are many prime numbers. Why do we choose them? This is unknown, this is probably because programmers have special advantages over them.
For Long, the hashCode code is:
public int hashCode() { return (int)(value ^ (value >>> 32));}
Is a 32-bit high or 32-bit low bitwise operation.
For Float, the hashCode code is:
public int hashCode() { return floatToIntBits(value);}
Similar to the equals method, the binary representation of float is treated as an int.
For Double, the hashCode code is:
public int hashCode() { long bits = doubleToLongBits(value); return (int)(bits ^ (bits >>> 32));}
Like equals, the Binary Expression of double is treated as long, and then hashCode is calculated by long.
We will also discuss equals and hashCode in subsequent chapters and further explain them.
ToString
Each packaging class also overrides the toString method and returns the string representation of the object. This is generally more natural and we will not go into details.
Comparable
Each packaging class also implements the Comparable interface in Java API. The Comparable interface code is as follows:
public interface Comparable<T> { public int compareTo(T o);}
<T> it is a generic syntax. As described in subsequent articles, T represents the comparison type and is passed in by the class that implements the interface. The interface has only one method compareTo. The current object is compared with the parameter object. If it is smaller than, equal to, or greater than the parameter,-, 1 should be returned respectively.
The implementation of each packaging class is basically compared based on the basic type value and will not be repeated. For Boolean, false is less than true. For Float and Double, the same problem exists as equals. The result of 0.01 and 0.1*0.1 is not 0.
Packaging class and String
In addition to the toString method, the packaging class also has some other String-related methods.
In addition to Character, each packaging class has a static valueOf (String) method, which returns the packaging class object according to the String representation, such:
Boolean b = Boolean.valueOf("true");Float f = Float.valueOf("123.45f");
There is also a static parseXXX (String) method that returns the basic type value according to the String representation, such:
boolean b = Boolean.parseBoolean("true");double d = Double.parseDouble("123.45");
There is a static toString () method, returns a string representation based on the basic type value, such:
System.out.println(Boolean.toString(true));System.out.println(Double.toString(123.45));
Output:
true123.45
For the integer type, strings can be represented in other hexadecimal formats, such as binary, octal, and hexadecimal notation, in addition to the default decimal format. The packaging class has static methods for mutual conversion, such:
System. out. println (Integer. toBinaryString (12345); // outputs the binary System. out. println (Integer. toHexString (12345); // output hexadecimal System. out. println (Integer. parseInt ("3039", 16); // hexadecimal resolution
Output:
11000000111001303912345
Common Constants
In addition to defining static methods and instance methods, some static variables are also defined in the packaging class.
Boolean Type:
public static final Boolean TRUE = new Boolean(true);public static final Boolean FALSE = new Boolean(false);
MAX_VALUE and MIN_VALUE are defined for all numeric types to indicate the maximum/minimum values that can be expressed. For example, for Integer:
public static final int MIN_VALUE = 0x80000000;public static final int MAX_VALUE = 0x7fffffff;
Float and Double also define some special values, such as positive infinity, negative infinity, and non-numeric values, such as Double:
public static final double POSITIVE_INFINITY = 1.0 / 0.0;public static final double NEGATIVE_INFINITY = -1.0 / 0.0;public static final double NaN = 0.0d / 0.0;
Number
The six numeric type packages have a common parent class Number, which is an abstract class and defines the following methods:
byte byteValue()short shortValue() int intValue()long longValue()float floatValue()double doubleValue()
With these methods, the wrapper instance can return any basic numeric type.
Immutable
The packaging classes are all immutable classes. The so-called immutable is that once an instance object is created, there is no way to modify it. This is enforced as follows:
- All packages are declared as final and cannot be inherited.
- The internal basic type value is private and declared as final
- No setter method defined
Why should we define it as an immutable class? Immutable makes the program simpler and safer, because you don't have to worry about the possibility of unexpected data rewriting. You can securely share data, especially in a multi-threaded environment. We will introduce threads in subsequent articles.
Summary
This section describes the basic usage of the packaging class, mutual conversion between basic types and packaging classes, automatic packing/unpacking, overwrite Object method, Comparable interface, mutual conversion with String, common constants, Number parent class, and immutable packaging class. In terms of basic daily use, in addition to Character, the content introduced by other classes is basically enough.
However, Integer and Long have some bit operation methods. We haven't introduced them yet. We haven't introduced most of the methods in Character, and we haven't discussed some of their implementation principles, let's continue exploring in the next two sections.
----------------
For more information, see the latest article. Please pay attention to the Public Account "lauma says programming" (scan the QR code below), from entry to advanced, ma and you explore the essence of Java programming and computer technology. Write with your heart, original articles, and retain all copyrights.
-----------
More original articles
Thinking logic of computer programs (1)-data and variables
Thinking logic of computer programs (5)-Why is an error in decimal calculation?
Thinking logic of computer programs (6)-How to recover from garbled code (I )?
Thinking logic of computer programs (8)-true meaning of char
Thinking logic of computer programs (12)-Basic Principles of function calls
Thinking logic of computer programs (17)-Basic Principle of inheritance implementation
Thinking logic of computer programs (18)-Why inheritance is a double-edged sword
Thinking logic of computer programs (19)-essence of interfaces
Thinking logic of computer programs (20)-Why abstract classes?
Thinking logic of computer programs (21)-nature of internal classes
Thinking logic of computer programs (23)-nature of enumeration
Thinking logic of computer programs (24)-exception (I)
Thinking logic of computer programs (25)-exception (lower)