Talking about == and equals in java

Today, see such a question, for example

Integer n1 = new Integer(2);

Integer n2 = new Integer(2);

System.out.println(n1 == n2); The displayed result is false;

System.out.println(n1.equals(n2)); the displayed result is true;

Why is n1 == n2 not equal to true? With this question in mind, I searched for a lot of information and summarized it as follows:

 

First, what does the relational operator "==" compare?

The following sentence is excerpted from the original words of the book "Java Programming Ideas":

"Relational operators produce a boolean result, and they compute the relationship between the values ​​of the operands".

This sentence seems simple, but it needs to be understood in detail. To put it simply, == is used to compare values ​​for equality.

     int  n=5;

     int  m=5;

     System.out.println(n==m); The display result is true , this is easy to understand, the value stored in variable n and variable m are both 3, which must be equal

 

     Integer n1 = new Integer(2);

     Integer n2 = new Integer(2);

     System.out.println(n1 == n2); The display result is false, why is it false, to understand this, we only need to understand the difference between basic data type variables and non-basic data type variables

     

    1) Basic data types

     There are 8 basic data types in Java midstream:

  Floating point: float(4 byte), double(8 byte)

  整型:byte(1 byte), short(2 byte), int(4 byte) , long(8 byte)

  Character type: char(2 byte)

  Boolean: boolean (The JVM specification does not specify the size of the space it occupies, only that it can only take literal values ​​"true" and "false")

  For the variables of these 8 basic data types, the variable directly stores the "value", so when the relational operator == is used for comparison, the "value" itself is compared. It should be noted that both floating point and integer types are signed types, while char is an unsigned type (the value range of char type is 0~2^16-1).

   2) Non-basic data types

     For variables of non-primitive data types, in some books it is called a variable of reference type. For example, n1 above is a variable of reference type, and a variable of reference type stores not the "value" itself, but the address in memory of its associated object.

     Integer n1 = new Integer(2);

     Usually the action of this statement is called creating an object, in fact, it contains four actions.

     1) The "new Integer" on the right uses the Integer class as a template to create an Integer class object (also referred to as an Integer object) in the heap space.

     2) The () at the end means that immediately after the object is created, the constructor of the Integer class is called to initialize the newly generated object. Constructors are definitely there. If you don't write it, Java will add a default constructor for you.

     3) "Integer n1" on the left creates an Integer class reference variable. The so-called Integer class reference is an object reference that can be used to point to an Integer object in the future.

     4) The "=" operator makes the object reference point to the Integer object that was just created.

     We can break this statement into two parts:

     Integer n1;

     n1 = new Integer(2);

     The effect is the same. In this way, it is relatively clear that there are two entities: one is the object reference variable, and the other is the object itself.

       Entities created in heap space are different from entities created in data segment and stack space. Although they are also real entities, we cannot see or touch them. Not only that,

       Let's take a closer look at the second sentence, what is the name of the object you just created? Some say it's called "Integer". No, "Integer" is the name of the class (object creation template).

       An Integer class can create an infinite number of objects based on it, and these objects cannot be called "Integer".

       The object doesn't even have a name, so there's no way to access it directly. We can only access objects indirectly through object references.

       In order to visualize objects, references, and the relationships between them, a metaphor that may be inappropriate can be made. The object is like a balloon so big that we can't hold it. A reference variable is a string that can be used to tie a balloon.

       If only the first statement is executed, and the second one has not been executed, the reference variable n1 created at this time has not yet pointed to any object, and its value is null. A reference variable can point to an object, or it can be null.

       It's a rope, a rope that hasn't been attached to any of the balloons. After executing the second sentence, a new balloon is made and tied to the rope n1. When we grab the rope, we grab the balloon.

      Simply put:

      n1 points to an object (n1 is also referred to as an object reference in many places), at this time, the variable n1 stores the storage address of the object it points to in memory, not the "value" itself, that is to say, it is not directly Stored value 2.

      So when comparing n1 and n2 with ==, the result is false. Therefore, they point to different objects, which means that they actually store different memory addresses.

 

      If executed:

      Integer n3 = n1;

      System.out.println("n1 == n3"); The display result is true because n3 points to the object pointed to by n1, that is, n1 and n3 point to the same object

 

2. What does equals compare?

  The equals method is a method in the base class Object, so all classes that inherit from Object will have this method. In order to understand the role of the equals method more intuitively, look directly at the implementation of the equals method in the Object class.

  The source code path of this class is: Object.java under the java.lang path of src.zip of C:\Program Files\Java\jdk1.6.0_14 (depending on the personal jdk installation path).

  The following is the implementation of the equals method in the Object class:

  

  Obviously, in the Object class, the equals method is used to compare whether the references of two objects are equal, that is, whether they point to the same object.

      Note that there is no: the equals method of the default Object class compares the addresses of two objects, which is the same as the result of ==.

      so why 

      Integer n1 = new Integer(2);

      Integer n2 = new Integer(2);

      System.out.println(n1.equals(n2)); The result is true? That's because the equals method in the class library Integer class has its own implementation, instead of comparing the storage addresses in the heap memory, they compare the values ​​that are not equal

Now there is a special case where

 E.g:

     String str1 = “Hello”;

     String str2 = "Hello";

     System.out.println("str1 == str2:" + (str1 == str2)); shows true

   why? It can be explained in this way that String constants are stored in the constant pool. During program compilation, for str1, the compiler first goes to the string constant pool to check if there is "Hello", if not, then open a memory space in the constant pool for storage "Hello"; then open up a space in the stack, name it "str1", the stored value is the memory address of "Hello" in the constant pool, go to Str2, the compiler first goes to the string constant pool to check whether there is "Hello" , After checking, it is found that there is "Hello", and then a space is opened up in the stack, named "str2", and the stored value is the memory address of "Hello" in the constant pool, so the memory addresses stored by str1 and str2 are the same.

   

   Therefore, we know: String is essentially an array of characters, with two characteristics: 1. The class cannot be inherited; 2. Immutable

    例如 String s1 = new String("myString") 和 String s1 = "myString"; 

       The first way is to define the process through the keyword new: During program compilation, the compiler first goes to the string constant pool to check whether there is "myString", if not, open a memory space in the constant pool to store "myString"; If it exists, there is no need to re-create the space, to ensure that there is only one "myString" constant in the constant pool, saving memory space. Then open up a space in the memory heap to store the new String instance, open up a space in the stack, name it "s1", and store the value of the memory address of the String instance in the heap. This process is to point the reference s1 to new. String instance

      The second way is to define the process directly: during program compilation, the compiler first goes to the string constant pool to check whether there is "myString", if not, open a memory space in the constant pool to store "myString"; if it exists , there is no need to re-open the space. Then open up a space in the stack, name it "s1", and store the value of the memory address of "myString" in the constant pool

Also: I need to mention String and StringBuffer

String s1 = "Hello";

System.out.println("s1.hashCode: " + s1.hashCode());  值为:s1.hashCode: 69609650

String s2 = s1;

s1 += "abcd";

System.out.println("s1.hashCode: " + s1.hashCode()); 值为:s1.hashCode:-1093921804

System.out.println("s1: " + s1); 值为: s1: Helloabcd

System.out.println("s2: " + s2); 值为:s2: Hello

The values ​​of s1 and s2 are different. Since String is immutable, s1 += "abcd" can be understood as: the modification of the existing String object is to recreate a new object, and then save the new value into it . That is, the value of s1 becomes the new value Helloabcd,

The stored memory address has also changed

 

StringBuffer sb1 = new StringBuffer("Hello");

System.out.println("sb1.hashCode: " + sb1.hashCode());  值为:sb1.hashCode: 1765413668

StringBuffer sb2 = sb1;

sb1.append(" world!");

System.out.println("sb1.hashCode: " + sb1.hashCode());  值为:sb1.hashCode: 1765413668

System.out.println("sb1: " + sb1); 值为: s1: Hello world!

System.out.println("sb2: " + sb2); 值为:s2: Hello world!

 

StringBuffer is a mutable object. When it is modified, it will not re-create the object like String.
           It can only be created through the constructor,
          StringBuffer sb = new StringBuffer("Hello");
          After the object is created, in memory It will allocate memory space and initially save a "Hello". Assign a value to it through its append method.
          sb.append("world!"); 

sb2 points to the references pointed to by sb1, they point to the same object, manipulate the same object, and get the content of the same object through them

 

In conclusion:

  1) For ==, if it acts on a variable of a basic data type, it directly compares its stored "value" for equality;

    If acting on a variable of reference type, the address of the pointed-to object is compared

  2) For the equals method, note: the equals method cannot act on variables of basic data types

    If the equals method is not overridden, the address of the object pointed to by the variable of the reference type is compared;

    If classes such as String and Date override the equals method, the content of the pointed object is compared.

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325352643&siteId=291194637