I heard that you still can't figure out = = and equals in java?

I believe that a lot of readers know about = = and equals, and they know about = = and equals. In fact, it may be because there are too many blog articles and so on. After a period of baptism, they get lost. This article is clear again. Of course, if I think this article is too verbose, of course, I have taken it into consideration, because I don't like long and long articles that are more verbose than rambling, after all, when you start java, you know something about it, so just remember one sentence: equals itself and== There is no difference. For basic data, they are comparison values. For reference types, they are the addresses of the objects they point to! Other classes override the equals method after inheriting the Object class, so what they represent is to compare the contents! The specific comparison depends on how you rewrite it.

Well, if you are interested, look at the following. Of course, the big guys who are not interested can make a point of praise, go straight, do not have to read it, they will see a * ah, Lou Zhu, you are simple and honest (leather is very happy).

1. The native equals() method itself is no different from "= ="!

In the essence of Java language, "= =" belongs to the operator of Java language, while equals is a method of root class Object.

As for the equals() method of the Object class, we can see its source code

  /*
     * @param   obj   the reference object with which to compare.
     * @return  {@code true} if this object is the same as the obj
     *          argument; {@code false} otherwise.
     * @see     #hashCode()
     * @see     java.util.HashMap
     */
public boolean equals(Object obj) {
    return (this == obj);
}

Yes, the underlying level of equals is actually "=", that is to say, the native equals() method itself is no different from "="! The only difference is that the basic type does not inherit the Object class, so the basic type does not have the equals() method, that is to say, the basic type can only use "= =" to determine whether the values are equal.

Since the native equals() method itself is no different from "= =" in any way, we can understand the use of "= =" operator!

The specific function of the operator "= =" is to compare whether the values are equal. There are two situations:

  • 1. For variables of basic data type, directly compare whether the stored "value" is equal;

  • 2. For variables of reference type, the comparison is whether the addresses of the objects pointed to are equal;

Here we can preliminarily confirm that the native equals() method itself is no different from "= ="! That's exactly what it does.

2. Override of equals() method

But the point is, because for the equals() method, I've been emphasizing the word native. Yes, let a lot of beginners confused point is here: equals() method rewrite!

In JDK, classes such as String and Date rewrite the equals method. Take String as an example. Readers interested here can take a look at the rewritten equals() method in the String class. Of course, skipping is not a big problem

/**
     * Compares this string to the specified object.  The result is {@code
     * true} if and only if the argument is not {@code null} and is a {@code
     * String} object that represents the same sequence of characters as this
     * object.
     *
     * @param  anObject
     *         The object to compare this {@code String} against
     *
     * @return  {@code true} if the given object represents a {@code String}
     *          equivalent to this string, {@code false} otherwise
     *
     * @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    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;
    }

From the source code, it can be seen that first, the method judges whether the object addresses pointed to are equal. If they are the same, it directly returns true. If they are not the same, the next if judgment is carried out. The second if judgment roughly means to compare whether the stored "values" are equal, that is, to compare the content values! If it is the same, return true. For example, two new string objects "AAA" and "AAA". Here, although the object address is not the same, the content is the same, so return true as well.

Here I want to give you a typical String example:

public static void main(String[] args) {
       String a = "Yichun";
       String b = new String("Yichun");
       String c = b; //Note that here is reference passing, which means that c also points to the memory address b points to
       
       System.out.println(a == b);  //false
       System.out.println(a == c);  //false
       System.out.println(b == c);  //true
       System.out.println(a.equals(b));  //true
       System.out.println(a.equals(c));  //true
       System.out.println(b.equals(c));  //true
    }

[Note: String type belongs to reference type]

Analysis:
(1)a == b? Does the address point to the same place? It's obviously different.

(2)a == c? Does the address point to the same place? It's obviously different.

(3)b == c? Does the address point to the same place? Obviously the content is the same, so it's true.

(4)a.equals( b )? Does the address point to the same content? Same.

(4)a.equals( c )? Does the address point to the same content? Same.

(4)b.equals( c )? Does the address point to the same content? Same.

Of course, you may still be a little confused. Then you can understand the above analysis in combination with the following picture, and you may suddenly realize it

OK. Can you understand now? You don't have to answer. I know you understand. Of course, it's worth noting that the method of intern() in String, first look at a program:

    public static void main(String[] args) {
       String a = "Yichun";
       String b = new String("Yichun");
       b=b.intern();

       System.out.println(a == b);  //true
       System.out.println(a.equals(b));  //true
    }

The meaning of the intern method is to check whether the string pool exists. If it exists, it will return to true directly. So here, first a will have one in the string pool, and then b.intern() will not create a new one as soon as it looks in the pool, and directly point B to it.

3. Why override the equals method?

I don't know if you have thought about it. Of course, the answer is also very simple, because programmers usually compare the content of strings. It's meaningless to compare whether the memory address is the same object. Rewriting equals method is very convenient to compare the content of strings.

In fact, in addition to such classes as String and Date, we often rewrite equals methods according to our own business requirements in actual development

Here's a chestnut:
Our demand is that if the names, ID numbers and genders of two student objects are equal, we think that the two student objects are equal, not necessarily the address of the student object is the same.

Personal information of student A (Name: Ruhua, gender: female, ID card No.: 123, address: Guangzhou), address of student A is 0x11,
Student B's personal information (Name: Ruhua, gender: female, ID card No.: 123, address: Shenzhen), and student A's object address is 0x12,

At this time, if we do not override the equals method of the Object, the returned value must be false. At this time, we need to override the equals() method according to our own needs. The specific rewriting code of equals method is as follows:

// Override equals method
	@Override
	public boolean equals(Object obj) {
		if(!(obj instanceof Student)) {
       // instanceof has processed obj = null
			return false;
		}
		Student stuObj = (Student) obj;
		// Equal object address
		if (this == stuObj) {
			return true;
		}
		// If the names, ID numbers and genders of the two objects are equal, we think the two objects are equal
		if (stuObj.name.equals(this.name) && stuObj.sex.equals(this.sex) && stuObj.IDnumber.equals(this.IDnumber)) {
			return true;
		} else {
			return false;
		}
	}

In the development of such a design, in order to meet our life! I won't believe you till now = = and equals!

However, when it comes to overriding the equals method, the following problem arises.

4. Do you want to override the hashCode() method after overriding the equals method?

Of course, this problem needs to be discussed, and there will be a lot of long speeches. Write an article like this when you have time to discuss this problem. Of course, the big guys in the garden have also written a lot! You can learn by yourself. This article is for a brief chat, just click here.

First, the hashCode() method is a method of the Object class. The source code is as follows:

/**
     * Returns a hash code value for the object. This method is
     * supported for the benefit of hash tables such as those provided by
     * {@link java.util.HashMap}.
     * <p>
     * The general contract of {@code hashCode} is:
     * <ul>
     * <li>Whenever it is invoked on the same object more than once during
     *     an execution of a Java application, the {@code hashCode} method
     *     must consistently return the same integer, provided no information
     *     used in {@code equals} comparisons on the object is modified.
     *     This integer need not remain consistent from one execution of an
     *     application to another execution of the same application.
     * <li>If two objects are equal according to the {@code equals(Object)}
     *     method, then calling the {@code hashCode} method on each of
     *     the two objects must produce the same integer result.
     * <li>It is <em>not</em> required that if two objects are unequal
     *     according to the {@link java.lang.Object#equals(java.lang.Object)}
     *     method, then calling the {@code hashCode} method on each of the
     *     two objects must produce distinct integer results.  However, the
     *     programmer should be aware that producing distinct integer results
     *     for unequal objects may improve the performance of hash tables.
     * </ul>
     * <p>
     * As much as is reasonably practical, the hashCode method defined by
     * class {@code Object} does return distinct integers for distinct
     * objects. (This is typically implemented by converting the internal
     * address of the object into an integer, but this implementation
     * technique is not required by the
     * Java<font size="-2"><sup>TM</sup></font> programming language.)
     *
     * @return  a hash code value for this object.
     * @see     java.lang.Object#equals(java.lang.Object)
     * @see     java.lang.System#identityHashCode
     */
    public native int hashCode();

It can be seen that the hashCode() method returns an int value. From the name of the method, it can be seen that its purpose is to generate a hash code. The main purpose of hash code is to input as key when hashing objects. It is easy to infer that we need hash code of each object to be as different as possible, so as to ensure the access performance of hash.

In fact, the default implementation provided by the Object class does guarantee that each Object's hash code is different (a hash code is returned based on the Object's memory address through a specific algorithm). Java adopts the principle of hash table. Hash algorithm, also known as hash algorithm, is to assign data directly to an address according to a specific algorithm. As a beginner can understand, what the hashCode method actually returns is the physical address of the Object store (actually not).

To know the function of hashCode, you must first know the collection in Java.

The elements of the Set List in Java are ordered and can be repeated; the Set elements are unordered but cannot be repeated. We all know that. But have you ever thought about the question: to ensure that the elements are not repeated, what should be the basis for judging whether the two elements are repeated?

Here is the Object.equals method for every mistake. However, if you check every additional element, when there are many elements, the number of element comparisons that are added to the collection is very high. That is to say, if there are 1000 elements in the collection now, when the 1001st element is added to the collection, it will call the equals method 1000 times. This will obviously reduce efficiency significantly.

How to solve it? We can verify it in the Java collection framework. Because HashSet is implemented based on HashMap, only the put method of HashMap can be seen here. The source code is as follows:

public V put(K key, V value) {
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)
            return putForNullKey(value);
        int hash = hash(key);
        //Here, the hash value is used to locate the approximate storage location of the object
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            //In the if statement, compare hashcode first, and then call equals() to compare
            //Because "& &" has the function of short circuit, as long as hashcode is different, there is no need to call equals method
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
}

As noted in the source code, "& &" has the function of short circuit, as long as the hashcode is different, there is no need to call the equals method. Yes, Java uses the principle of hash table. Hash table has superior query performance, just like multiplication table 2 * 3 = 6, you can easily know, but hash table will inevitably have hash conflict, but the probability is very low.

This is designed so that when a collection wants to add a new element, it calls the hashCode method of the element first, and then it can be located in the physical location where it should be placed.
If there is no element in this location, it can be stored directly in this location without any further comparison. If there is already an element in this location, call its equals method to compare with the new element. If it is the same, it will not be saved. If it is different, its address will be hashed. So there is a problem of conflict resolution. In this way, the actual number of calls to equals method is greatly reduced, almost only one or two times.

Therefore, it is not necessary to rewrite the hashCode method when overriding the equals method. Only when using the HashMap,HashSet and other Java sets to rewrite the equals method, it is necessary to rewrite the hashCode method. It's OK to just override the equals() method without using a hash table.

Java officials suggest that overriding equals() requires overriding the hashCode() method. After all, Java collections are often used in real development scenarios

5. Relationship between eqauls method and hashCode method

Java defines eqauls method and hashCode method as follows:

1. If two objects equals true, their hashcode s must be equal.
2. If two objects are equal to false, their hashcode s may be equal.
3. If two objects have the same hashcode, equals is not necessarily true.
4. If the two objects hashcode are not equal, equals must be false.

In the end, if there are any deficiencies or irregularities, please correct and criticize. Thank you very much!

Welcome to my official account. There are some java learning materials and a large number of Java e-books, such as Zhou Zhiming's in-depth Java virtual machine, Java programming ideas, core technology volumes, big talk design patterns, Java Concurrent Programming, actual combat... Java are all Bible, not to mention fast Tomcat car, how do we go! The most important thing is to discuss technology together, yearn for technology, and pursue technology. It's said that when we come, we will be friends

Keywords: Java Programming JDK Tomcat

Added by sameerni on Wed, 08 Apr 2020 15:51:42 +0300