There are two ways to judge equality in Java: (1) the "= =" relational operator (2) equals () method. Obviously, only "= =" is used between basic data type variables. Both of these methods are legal. But there are many beginners who make mistakes in "judging the equality of Java", where we thoroughly dissect the mysteries at the JVM's operational level. If you are not familiar with the JVM specification, before reading this article, learn about the five run-time data areas that are managed in memory, especially the heap and Java stacks (seeJava Virtual Machine architecture ), when you run a program in the JVM.
★ The comparison nature of the "= =" operator
Let's take a look at two pieces of source code:
Java code
// Code Listing 1: "= =" Comparison of an integer wrapper Integer n1=new Integer (1); Integer n2=new integer (1); if // false
Java code
// Code Listing 2: "= =" Comparison of integer variables int n3=1; int n4=1; if // true
The result of code 1 surprises us. But before explaining this phenomenon, let us first clarify an important point of knowledge:
The JVM runs a Java program, which in memory will open up a run-time data area called " heap ". All of the class objects created during the run are stored in this area (to be exact, the non-static, extraordinary instance data of the class is stored in the heap). More importantly, the heap space for these objects has its own address, which is what we often call object references . The object reference, not the data in the object, is stored either in the method area or in the Java stack.
Let's take a look at the execution instructions in the JVM for the above two pieces of code:
Code 1 bytecode Instruction code
0NewJava.lang.Integer [16]//allocates an integer object n1 space in the heap and presses the object reference (heap address) into the operand stack3 DUP//Copy the reference of the object N1 into the operand stack4 iconst_1//presses a constant 1 of an integral length into the operand stack5 Invokespecial Java.lang.Integer (int) [18]//A reference to the integer constant 1 and the object n1 that initializes the instance data of the object N1 in the heap8 Astore_1 [N1]//pops a reference to the object N1 and saves it in the 1th position of the local variable area. 9NewJava.lang.Integer [16]//object N2 Ibid .12DUP13iconst_1Invokespecial Java.lang.Integer (int) [18] astore_2 [N2]//Save a reference to the object N2 to the 2nd position in the local variable areaAload_1 [N1]//Press the N1 object reference in local variable 1 into the operand stackAload_2 [N2]//Press the N2 object reference in local variable 2 into the operand stack23 If_acmpne//pops a reference to the n1,n2 of the operand stack and compares the two reference values for equality. 22return
Code 2 bytecode Instruction code
//////////// //return
As can be seen from Code 1 bytecode directives, the integer wrapper object n1 and N2 Compare object references (directive: If_acmpne 23), two objects in the heap are two different spaces, natural addresses are not the same.
and code 2 bytecode instructions can be seen, integer variables n3 and N4 compared to the integer constant value, are 1, naturally the same.
the comparative Essence of ★equals method
Or to see a source code:
Code Listing 3: Equals method code for an integer wrapper
Integer n1=new Integer (1); Integer n2=new integer (1); if // true
The following is the <Integer> equals (Object obj) method source code, which compares an integer value.
Integer.equals Source Code Code
Public Boolean equals (Object obj) { ifinstanceof Integer) { return value = = ((Integer) obj). Intvalue (); } return false ; }
is the Equals method comparing the object's data values? This is of course very much related to how the Equals method of the class to which the object belongs is implemented. Let's take another look at the code:
The Equals method code of the custom class value
Value v1=new//value is a custom class, where the Equals () method is not defined. value v2=new value (1if//false
Object in Java is the ancestor of all classes, since value does not define the Equals () method. Then the above code call is naturally the Equals () method of object. Let's look at the source code of the <Object> equals (Object obj) method and compare the reference of the object with "= =".
Java code
Public Boolean equals (Object obj) { return ( this = = obj);}
If we want to achieve the purpose of comparing the data values in the object with the Equals method, we must implement the Equals method in the specified class to overwrite the Equals method of object. Never, if not overridden, the default behavior of the Equals method is still to compare object references.
Through above, we have a clear understanding of the nature of "= =" and "equals", but the unthinkable will still happen.
1. "Equal comparison" doubts caused by the particularity of string type
Take a look at the two source code:
Code 4:string Equality Comparison code for type
String s1=New string ("AAAA"); string S2=new string ("AAAA"if//if// True
Code 5:string Equality Comparison code for type
String s3= "AAAA"; String S4= "AAAA"if//if//true
Code 4 is good to understand, but code 5 is a bit confusing. Before we explain, we need to clarify a few questions:
(1) string is a class, not a basic data type. S1,s2 are object instances, not basic data variables.
(2) String s3= "AAAA"; is a relatively special method of object creation. It involves issues related to the constant pool in the JVM management method area and the detention string Object . There is a detailed summary in the article "String in Java" .
The following is a look at the instructions for the "= =" Comparison string object in code 5 when the JVM is running:
Instruction code for Code 5
0 LDC <string "AAAA" > [] // put the address of a string object in the heap of a constant pool that is pointed to by the "AAA" string constant into the operand stack 2 astore_ 1 // pop up the stack top value and store it in the 1th position of the local variable area 3 LDC <string "AAAA" > [+] // Hold the address of the string object in the heap that points to the "AAA" string constant in the constant pool into the operand stack 5 astore_2 // eject stack top value and store it in the 2nd position of the local variable area 6 // Press the local variable 1 into the operand stack 7 // Press the local variable 2 into the operand stack 8 if_acmpne 11 // eject two stack top values for comparison
Obviously, "= =" is still compared to the address. However, because of the indentation of the operand stack is the address of the same detained string object that the string constant "AAA" points to. Therefore S3 and S4 Save the same address, the natural "= =" Comparison results are the same.
2. The "Equality comparison" puzzle caused by the automatic packing (autoboxing) mechanism of integer type
Keep looking at the two pieces of code
Code Listing 6: Code for an integer wrapper object
Integer a=127; integer b=127if// Result: True
Code Listing 7: code for an integer wrapper object
Integer c=128; integer d=128if// Result: false
Code 6 and Code 7 almost the same statements have different results, it is very confusing. There are a few things to clarify before explaining this:
(1) The source code of a, B, C, D is not an integer variable, but an integer wrapper object. This point is for sure.
(2) Integer a=127; This form of definition is more special. The reason is that during the compilation, the compiler did a little bit of action. It automatically calls the integer.valueof (int) method to package the integer constant 127 (autoboxing) into the wrapper class. We call it the automatic packing mechanism . This means that the JVM is running an Integer a=integer.valueof (127);
But still did not solve the code 7,8 different doubts ah? Let's take a look at the source code for integer.valueof (int):
Java code
/*** Returns A <tt>Integer</tt> instance representing the specified * <tt>int</tt> value. * If A New <tt>Integer</tt> instance isn't required, this method * should generally being used in preference to the CO Nstructor * {@link#Integer (int)}, as this method was likely to yield * significantly better space and time performance by caching * Freq Uently requested values. * * @paramI an <code>int</code> value. *@returna <tt>Integer</tt> instance representing <tt>i</tt>. *@since1.5*/ Public StaticInteger ValueOf (inti) {Final intoffset = 128; if(I >= -128 && i <= 127) {//must cache returnIntegercache.cache[i +offset]; } return NewInteger (i);}Private Static classIntegercache {PrivateIntegercache () {}Static FinalInteger cache[]=Newinteger[-(-128) + 127 + 1]; Static { for(inti = 0; i < cache.length; i++) Cache[i]=NewInteger (i-128); }}
Look at the source code of the integer know, in fact, interger each of the values between -128~127 established a corresponding integer object, and these objects are organized into a cache array, similar to a buffer. The integer object in this cache array is safe to reuse. That is, the integer a=127, and the integer b=127, and the reference A, a, b are the addresses of the new Integer (127) object in the cache array. So the A==b in code 6 is naturally true.
Note, however, that the cache array stores only the integer objects between -128~127. For other values, the shaping wrapper, such as the integer c,d=128 in code 7, creates two completely different integer objects in the heap to store 128. Two objects have different addresses.
Here is a point: if it is an integer a=new integer (127), this general form creates an integer that does not have a cache array. Only an integer a=127 or integer a=integer.valueof (127) can use the cache array in such a way. And the shaping value of the wrapper is between -128~127.
In fact, this little trick really does cause trouble for beginners. But it is an important application in Java performance optimization. We all know that the constant opening of new objects in the heap costs a great price. When we need a large number of integer objects in the -128~127 range, such a cache buffer reduces the creation of a large number of objects, which can be imagined when the efficiency increases.
"The same" relationship that "doubts" make people headache