Understand the difference between ==, equals, and hashCode in java in ten minutes

Let’s start with a summary:

  1. The == operator is to judge whether two objects are the same object, that is, whether their addresses are equal
  2. equals and == in the object class are equivalent
  3. Overriding equals is more about pursuing the logical equality of two objects. You can say that the value is equal, or the content is equal. (After overwriting, always overwrite hashCode when overwriting equals)
  4. HashCode is used to return the hash value of the object. It is mainly used for the quickness of search. Because the hashCode is also in the Object object, all Java objects have a hashCode. In the hash structure of HashTable and HashMap, both Find the position in the hash table by hashCode.

1. Java == operator difference

Data types in java can be divided into two categories:

1. Basic data types , also known as primitive data types

To compare byte, short, char, int, long, float, double, boolean, use the double equal sign (==), and compare their values .

2. Reference type (class, interface, array)

When they use (==) to compare, they compare their storage addresses in memory . Therefore, unless it is the same new object, the result of their comparison is true, otherwise the result of the comparison is false.

Objects are placed in the heap, and the reference (address) of the object is stored in the stack . It can be seen that'==' compares the values ​​in the stack. If you want to compare whether the contents of the objects in the heap are the same, then you must override the equals method .

2. There is == operator in Java, why do you need equals?

The role of equals() is to determine whether two objects are equal. The definition in Object is:

//equals与==是等效的
public boolean equals(Object obj) {
        return (this == obj);
    }

This shows that before we implement our own equals method, equals is equivalent to ==, and the == operator judges whether two objects are the same object, that is, whether their addresses are equal. Overriding equals is more about pursuing the logical equality of two objects. You can say that the value is equal, or the content is equal.
Rewrite of equals method in String.java

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

Here are five points to note about equals again:

  1. Reflexivity: For any reference value X, the return value of x.equals(x) must be true.
  2. Symmetry: For any reference value x, y, if and only if the return value of y.equals(x) is true, the return value of x.equals(y) must be true;
  3. Transitivity: if x.equals(y)=true, y.equals(z)=true, then x.equals(z)=true
  4. Consistency: If there is no change in the comparison object, the result of the comparison should not change.
  5. Non-nullability: For any non-null reference value X, the return value of x.equals(null) must be false

In the following conditions, the goal can be achieved without overwriting equals:

  • Each instance of the class is essentially unique: those that emphasize the active entity and do not care about the value, such as Thread, which thread we care about, can be compared with equals at this time.
  • I don’t care whether the class provides a logical equality test function: users of some classes will not use its comparison function, such as the Random class. Basically no one will compare two random values.
  • The superclass has already overridden equals, and the subclass only needs to use the behavior of the superclass: For example, if equals has been overwritten in AbstractMap, then this function is also needed in the behavior of the inherited subclass, and it does not need to be implemented.
  • If the class is private or package-level private, the equals method is not needed: At this time, you need to override the equals method to disable it:
@Override public boolean equals(Object obj) { throw new AssertionError();}

3. What's the use of hashCode?

The hashCode() method returns a value, as can be seen from the name of the method, its purpose is to generate a hash code. The main purpose of the hash code is to input as a key when hashing an object. From this, it is easy to infer that we need the hash code of each object to be as different as possible to ensure the access performance of the hash. In fact, the default implementation provided by the Object class does guarantee that the hash code of each object is different (a hash code is returned through a specific algorithm based on the memory address of the object). Java uses the principle of hash tables. Hash is actually a personal name. Because he proposed a hash algorithm concept, it was named after him. Hash algorithm is also called hash algorithm, which directly assigns data to an address according to a specific algorithm . Beginners can understand that the hashCode method actually returns the physical address of the object storage (it may not actually be).

3.1 The role of hashCode

To understand, you must first know the collections in Java.  
In general, there are two types of collections in Java, one is List, and the other is Set. The elements in the former set are ordered, and the elements can be repeated; the elements in the latter are disordered, but the elements cannot be repeated.

Then there is a more serious problem: if you want to ensure that the elements are not repeated, what should be the basis for judging whether two elements are repeated?

This is the Object.equals method. However, if the check is performed every time an element is added, when there are many elements, the number of comparisons of the elements added to the set will be very large. In other words, if there are already 1000 elements in the collection, when the 1001st element is added to the collection, it will call the equals method 1000 times. This will obviously greatly reduce efficiency.
Therefore, Java uses the principle of hash tables.

In this way, when a new element is added to the collection,

Call the hashCode method of this element first, and you can locate the physical location where it should be placed at once.

If there is no element in this position, it can be stored directly in this position without any comparison;

If there is already an element at this position, call its equals method to compare with the new element. If it is the same, it will not be stored. If it is not, it will hash other addresses. So there is a conflict resolution problem here. In this way, the number of actual calls to the equals method is greatly reduced, almost only once or twice.

 

Knowledge expansion diagram (summarized and expanded as follows):

 

Guess you like

Origin blog.csdn.net/qq_27828675/article/details/102551384