What are the equals and Hashcode methods?

The Object class is a superclass of Java. Each class directly or indirectly inherits from the Object class. Object provides eight basic methods, including equals and HashCode.

Equals: The equals method in the Object class checks whether one Object is equal to another. In the case of the Object class, this method determines whether two objects have the same reference. If two objects have the same reference, they must be equal.

The hashcode method is used to obtain the hashcode, which is an integer value exported from an object. The hashcode is random. If x and y are two different objects, x.hash code () and y.hash code () will not be the same

Why override equals and HashCode methods?

There are two main reasons why we need to override equals and HashCode:

1. We already know that the equals method in Object is used to determine whether references to two objects are the same, but sometimes we don’t need to determine whether references to two objects are equal, we just need to determine whether a particular state of two objects is equal. For example, for two articles, I just need to judge whether the links of the two articles are the same. If the links are the same, then they are the same article. I don’t need to compare other attributes or reference addresses.

2. In some business scenarios where we need to use a custom class as the key of a hash table, we need to rewrite it because without specific modifications, the hashcode generated by each object is almost impossible to be the same. Hashcode determines the position of the element in the hash table, and equals determines the judgment logic. Therefore, in special cases, we need to rewrite these two methods to meet our requirements.

Let’s use a small Demo to simulate a special scenario to better understand why we need to override equals and Hashcode methods. Our scenario is: We have a number of articles, and I need to determine if the articles are already in the Set, and the two articles are the same as long as they have the same access path.

Let’s create an article class to store article information. The specific design of the article class is as follows:

class Article{
    // Article path
    String url;

    // Title of the article
    String title;
    public Article(String url ,String title){
        this.url = url;
        this.title = title;
    }
    public String getUrl(a) {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getTitle(a) {
        return title;
    }
    public void setTitle(String title) {
        this.title = title; }}Copy the code

We don’t override equals and HashCode in this class, so we use equals and hashCode in the superclass Object. In case you haven’t seen the equals and hashcode methods of the Object class, let’s look at the equals and hashCode methods of the Object class:

After that, let’s write a test class. The test class code is as follows:

public class EqualsAndHashcode {
    public static void main(String[] args) {
        Article article = new Article("www.baidu.com"."Google it.");
        Article article1 = new Article("www.baidu.com"."Pit B Baidu");

        Set<Article> set = newHashSet<>(); set.add(article); System.out.println(set.contains(article1)); }}Copy the code

In the test class, we instantiate two article objects, the url of the article object is the same, but the title is different. We store the article object into the Set to determine whether the article1 object exists in the Set. According to our assumption, the urls of the two articles are the same. The two articles should be the same article, so we should return True here and run the Main method. The results are as follows:

Override equals

In this case, we first use the equals method generated by IDEA tool and then return the last logic to modify it. The specific writing rules will be introduced below. Finally, our equals method looks like this

/** * override equals () to make two articles equal as long as they have the same URL@param o
 * @return* /
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null|| getClass() ! = o.getClass())return false;
        Article article = (Article) o;
        return Objects.equals(url, article.url);
    }
Copy the code

If you run Main again, you’ll find that it’s still False. Why is that? A hash table is an array with a linked list attached to each array. The nodes of the linked list are used to store information about objects. The location of objects in the array is determined by hashcode(). So when we call the add(Object O) method of the HashSet, we first locate the corresponding array location based on the return value of O.hashcode (). If there are no nodes in the array location, we put O there, and if there are already nodes, we attach O to the end of the list. Similarly, when contains(Object O) is called, Java uses the return value of hashCode() to locate the corresponding array, and then calls equals() on each node in the list to determine whether the Object in that node is the Object you want.

Because we overwrite only equals and not hashcode, the hashcode values of the two articles are different, which maps to different positions in the array. When we call set.contains(article1), the hash table might look something like this:

The article object is mapped to array subscript 0, and the article1 object is mapped to array subscript 6, so return False if not found. Since we can’t just rewrite equals, we’ll rewrite hashCode as well.

2. Rewrite the hashCode method

Like equals, we use the hashcode method that the IDEA editor generated for us, with minor changes, as follows:

    @Override
    public int hashCode(a) {
        return Objects.hash(url);
    }
Copy the code

After rewriting the HashCode method, we run Main again, and this time we get True, which is exactly what we want. After overriding the equals and hashcode methods, look in the hash table as shown below:

The article1 object is also mapped to the index 1 of the array. The article data node exists at the index 1 of the array, so the article1.equals(article) command is executed. Since we’ve overridden the equals method of the Article object, this will determine whether the URL attributes of the two Article objects are equal or not, and return True if they are, which they clearly are, so return True here and get the result we want.

How do I write the equals and HashCode methods?

Need to override equals yourself? Ok, I’m going to rewrite it, crackling out the following code:

public boolean equals(Article o) {
    if (this == o) return true;
    if (o == null| |! (oinstanceof  Article)) return false;
    return o.url.equals(url);
}
Copy the code

Is that right? The logic looks fine, but the equals method argument becomes Article. This has nothing to do with overriding equals (Article). It does not override equals (Object).

So how do you override equals? And the equals relation is implemented in the Object as follows: The equals method provides a equivalence relation. It has the following properties:

  • Reflexivity: for any non-empty reference to x, x.equals(x) must return true
  • Symmetry: For any non-empty references x and y, x. quals(y) must return true if and only if y.quals (x) returns true
  • Transitivity: For any non-empty reference x, y, z, x. quals(z) must return true if x.quals (y) returns true and y.quals (z) returns true
  • Consistency: For any non-empty reference x and y, multiple calls to x.equals(y) must always return true or always return false if the information used in the EQUALS comparison has not been modified
  • Non-null: for any non-null reference to x, x.equals(null) must return false

Now that we know the general convention for writing equals, let’s rewrite the equals() method of the Article object again by referring to the general convention for overriding equals. The code is as follows:

    // Use the @override flag to avoid the above error
    @Override
    public boolean equals(Object o) {
        // check whether it is equal to itself
        if (this == o) return true;
        // 2. Check whether the o object is empty or of type Article
        if (o == null| |! (oinstanceof  Article)) return false;
        // 3. Parameter type conversion
        Article article = (Article) o;
        // check whether the urls of two objects are equal
        return article.url.equals(url);
    }
Copy the code

This time we use the @override flag to avoid the error of our previous Override. Because there is no Article method in the parent class, the compiler will report an error, which is very programmer friendly. Next, we verify reflexivity and non-emptiness, and finally judge whether the urls of the two objects are equal. This equals method is much better than the one above, and basically nothing wrong with it.

The effective Java book summarizes a recipe for writing high-quality equals methods as follows:

  • 1. Use the == operator to check whether the argument is a reference to the object. If so, return true.
  • 2. Use the instanceof operator to check that the parameter has the correct type. If not, return false.
  • 3. Convert the parameter to the correct type. Because the transformation has already been handled in Instanceof, it is guaranteed to succeed.
  • 4. For each “important” attribute in the class, check whether the parameter attribute matches the corresponding attribute of the object.

Now that we’ve seen how to override equals, let’s see how to override hashCode. We know that hashCode returns a method of type int

@Override
 public int hashCode(a) { 
 return 1; 
 }
Copy the code

Is that right? True or false, let’s look at hashcode in Object:

  • 1. When the hashCode method is repeatedly called on an object during an application execution, it must always return the same value if no information has been modified in the equals method comparison. Each execution from one application to another can return inconsistent values.
  • 2. If two objects are equal according to equals(Object), then a call to hashCode on both objects must produce the same integer.
  • 3. If two objects are not equal according to equals(Object), calling hashCode on each Object is not required to produce different results.

Hashcode doesn’t seem to have any problems with this, but you should know that hash tables, if written this way, are nullated for hash tables such as HashMap and HashSet, where elements are mapped into the array depends on Hashcode, Our Hashcode always returns 1, so that every element maps to the same location and the hash table degrades to a linked list.

In combination with the hashcode specification and hash table, to rewrite a hashcode method of high quality, you need to ensure that each element produces a different Hashcode value as much as possible. In the JDK, each reference type overwrites the Hashcode function. Let’s look at how hashCode is overwritten in the String class:

public int hashCode(a) {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}
Copy the code

This hashcode method is still very well written. Personally, I prefer to use official stuff. I think they think a lot more about it than we do, so our Article class hashcode method can be written like this

    /** * overrides the hashcode method to return the hash value * based on the URL@return* /
    @Override
    public int hashCode(a) {
        return url.hashCode();
    }
Copy the code

We call the HashCode method of String directly. At this point we’ve overridden our equals and hashCode methods, ending with a summary from effective Java.

  • 1. When overriding equals, also override hashCode
  • 2. Don’t let the equals method try to be too smart.
  • 3. Do not replace Object with another type in the equal method declaration.

Article insufficient place, hope everybody gives directions a lot, common study, common progress

The last

Play a small advertisement, welcome to scan the code to pay attention to the wechat public number: “The technical blog of the flathead brother”, progress together.