How to write high-quality equals and hashcode methods?

What are the equals and hashcode methods?

This is from the Object class to begin with, we know that the Object class is a superset of Java classes, each directly or indirectly inherit Object class that provides eight basic methods in Object, equals method and hashcode method is one two.

equals method : equals in class Object Method for detecting whether an object is equal to another object, Object class, the method determines whether the two objects have the same reference, if two objects have the same reference, they must be equal.

hashcode method : used to obtain a hash code, a hash code is derived by a target integer value, the hash code is not regular, if x and y are two different objects, then x.hashCode () and y. hashCode () does not substantially identical

Why override equals and hashcode methods?

Why override equals method and hashcode method, I think that is largely based on the following two points to consider:

1, we already know that in the Object equals method is used to determine whether the two references to the same object, but sometimes we do not need to determine whether two object references are equal, we only need two objects of a particular state equality. For example, for two articles, I link the two articles as long as the judge is the same, if the same link, then they are the same article, I do not need to compare other attributes or referenced address is the same.

2, in some business scenarios, we need to use a custom class as the key to the hash table, this time we need to be rewritten, because if not, then certain modifications, hashcode each object produced essentially the same as impossible, the hashcode determines the position of the element in the hash table, equals determines the decision logic, so under special circumstances would need to override these two methods in order to meet our requirements.

We use a little bit special to simulate Demo scene, let us better understand why the need to override equals and hashcode methods, our scenario is: we have a lot of articles, I need to determine whether the article already exists Set in two articles the same conditions were the same access path.

Well, we write Demo hands together and let us build a class paper to store information article, the article class specific design as follows:

class Article{
    // 文章路径
    String url;

    // 文章标题
    String title;
    public Article(String url ,String title){
        this.url = url;
        this.title = title;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
}
复制代码

Article class has a path, heading two properties in this class we did not override equals and hashcode method, so here uses super class Object equals and hashcode methods, in order to prevent you have not seen equals in class Object and hashcode methods, let's look together the Object class equals and hashcode methods:

After reading it, then we write a class test, test class code is as follows:

public class EqualsAndHashcode {
    public static void main(String[] args) {
        Article article = new Article("www.baidu.com","百度一下");
        Article article1 = new Article("www.baidu.com","坑B百度");

        Set<Article> set = new HashSet<>();
        set.add(article);
        System.out.println(set.contains(article1));

    }
}
复制代码

In the test class, we instantiate two objects articles, url article objects are the same, the title is not the same, we will be credited to the article subject Set in determining whether article1 Set object exists in accordance with our assumptions, the same two articles Url, the two articles should be the same article, so here it should give us a return True, we run the Main method. The results obtained are as follows:

We see the results but not what you want True False, the reason is very simple, because the same access path two articles is that the same article, which we defined the rules, we do not tell our program this rule, we no override equals and hashcode method, the system used at the time of judgment is the object class equals and hashcode default method, the default method of determining equals two objects are referenced address is the same, there is certainly not the same, to give the answer is False. We need to tell us equal rules of procedure, then we'll rewrite the equals method.

1, a method override equals

Here we start with the equals method IDEA tool generates, the last logical look like a return to the logic modification, specific written rules we will explain below. Finally, we are equals as follows

/**
 * 重写equals方法,只要两篇文章的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);
    }
复制代码

Main method run once again, you will find or False, this is why? I have two objects are equal judgment tells the program logic, do not worry, let's chat hash table and let us know using the hash table is an array of structures + linked list, each carrying an array of hanging chain , node list used to store the object information, and the object falls from the position of the array hashcode (). So when we call the HashSet add (Object o) method, based on first o.hashCode () returns a value corresponding to the array location positioning, if not the node position array, where if o put, if you have there nodes, and linked to the end of the list put o. Similarly, when the call contains (Object o), Java will pass the return value hashCode () to locate the appropriate array location, and then in turn call equals the corresponding node in the linked list () method to determine nodes in whether the object is an object that you want.

Since we only override the equals method does not override the hashcode method, so the two articles hashcode value is not the same, this is mapped to the location of the array is not the same, calling set.contains (article1) method, in the hash table situation may be as shown below:

article object is mapped to the array subscript 0 position, article1 objects are mapped to the position labeled 6 array, it is not found return False. Since only override equals method does not work, then we also rewrote the hashcode method.

2, a method override hashcode

With the equals method, we also use the idea editor to help us generate the hashcode method, only need a slight change can be, hashcode specific code is as follows:

    @Override
    public int hashCode() {
        return Objects.hash(url);
    }
复制代码

After rewriting good hashcode method, once again running the Main method, the result obtained is True, this is what we would want the results. After overwriting equals and hashcode methods, in FIG lookup hash table as shown:

First article1 objects will be mapped to the array index for the 1 position, there is article data node 1 position in the array index, it will execute article1.equals (article) command, because we rewrite the equals method of Object Article whether this will determine the url property of two Article objects are equal, if equal returns True, apparently equal here, so here it returns True, to get the results we want.

How to write equals and hashcode methods?

Need to override equals method yourself? Okay, I'll rewrite, crackling and win the following code:

public boolean equals(Article o) {
    if (this == o) return true;
    if (o == null || !(o instanceof  Article)) return false;
    return o.url.equals(url);
}
复制代码

Written on it? While inside the logic of fancy no problem, but the parameter equals method became Article. In fact, you follow this method does not override equals half wool relations, which is totally redefines the equals method a parameter of type Article, and not to cover the Object class equals method.

Then how to override equals methods? In fact, there is a general provision equals method when you override equals method, you'll need to override common convention equals method has the following specifications in Object: equals method implements an equivalence relation (equivalence relation). It has the following attributes:

  • Reflexive : for any non-null reference x, x.equals (x) must return true
  • Symmetry : For any reference x and y, x.equals (y) must return true if and only if y.equals returns true (x)
  • Transitive : for any reference x, y, z, if x.equals (y) returns true, y.equals (z) returns true, x.equals (z) must return true
  • Consistency : For any non-null reference x and y, if the information used in equals comparisons is not modified, the x.equals (y) multiple calls must always return true or consistently return false
  • Nonemptiness : For any non-null reference x, x.equals (null) must return false

Now that we know the common convention to write the equals method, then we refer to common convention to rewrite the equals method, again to rewrite Article object equals () method. code show as below:

    // 使用 @Override 标记,这样就可以避免上面的错误
    @Override
    public boolean equals(Object o) {
        // 1、判断是否等于自身
        if (this == o) return true;
        // 2、判断 o 对象是否为空 或者类型是否为 Article 
        if (o == null || !(o instanceof  Article)) return false;
        // 3、参数类型转换
        Article article = (Article) o;
        // 4、判断两个对象的 url 是否相等
        return article.url.equals(url);
    }
复制代码

This time we used @Override mark, so that we can avoid mistakes on a rewrite because the parent class and no parameters for the method Article, so the compiler will complain, which is very programmer friendly. Next we had, validation of non-empty reflexivity, url final judgment of the two objects are equal. This equals to that method is much better, basically nothing much wrong with the above ratio.

In the effective-java to write the book summarized a set of high-quality equals method formula, formula is as follows:

  • 1, == operator to check whether a reference parameter for the object. If so, it returns true.
  • 2, using the parameters instanceof operator to check whether the correct type. If not, false is returned.
  • 3, the parameter is converted to the correct type. Because the conversion operation in instanceof has been treated, so it is sure to be successful.
  • 4, for each class of "important" attribute, check whether the attribute parameter corresponding to the object attributes match.

We already know how to rewrite the equals method, then went together to learn how to override the hashcode method, we know hashcode method returns an int type of method, it was easy to handle, like this rewrite on the line

@Override
 public int hashCode() { 
 return 1; 
 }
复制代码

Written on it? Whether right or wrong before, we first look at the provisions in the Object hashcode of:

  • 1, when the process of execution of the application, if the comparison process does not modify any equals information hashCode method is called repeatedly on an object, it must always return the same value. From one application to another application executed every time the value returned may be inconsistent.
  • 2, if two objects based equals (Object) method is relatively equal, then the two results on the object by invoking the hashCode must produce the same integer.
  • 3, if the two objects are not equal according to the comparison equals (Object) method on each object call hashCode must produce different results is not required.

According to the provisions of hashcode of view, this seems to have no problem writing, but you should know that the hash table, if so write, for HashMap and HashSet such as a hash table, the direct destroy them, and Kazakhstan in the list, elemental mapping to which the position of the array by hashcode decision, but we always return the hashcode 1, in this case, each element will be mapped to the same location, the hash table will degenerate into a linked list.

And combined hash hashcode specification point of view, to re-write a high quality hashcode method, it is necessary to ensure that each element as hashcode produce different values, in the JDK, each reference type are rewritten hashcode function, we see how the String class hashcode is rewritten:

public int hashCode() {
    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;
}
复制代码

The hashcode method of writing is still very good, I personally prefer to use the official stuff, I feel sure they consider a lot more than we do, so our Article class hashcode method can be written like this

    /**
     * 重写 hashcode方法,根据url返回hash值
     * @return
     */
    @Override
    public int hashCode() {
        return url.hashCode();
    }
复制代码

We called directly hashcode method of the String object. This our equals method and hashcode methods are rewritten over, finally some effective-java which are summarized at the end of it.

  • 1, when the override equals method, but also to rewrite the hashCode method
  • 2, do not let the equals method of trying to be too clever.
  • 3, in the method declaration equal, the Object parameter will not replace other types.

The inadequacies of the article, hope a lot of pointing, learn together, and common progress

At last

Play a little advertising, welcomed the focus on micro-channel scan code number public: "flat head brother of technical Bowen" progress together.

Flathead brother of technical Bowen

Guess you like

Origin juejin.im/post/5d8b4b3df265da5b591b513d