简体   繁体   English

当我覆盖equals()方法时,为什么要覆盖hashCode()?

[英]Why should I override hashCode() when I override equals() method?

Ok, I have heard from many places and sources that whenever I override the equals() method, I need to override the hashCode() method as well. 好吧,我从许多地方和消息来源得知,每当我覆盖equals()方法时,我也需要覆盖hashCode()方法。 But consider the following piece of code 但请考虑以下代码

package test;

public class MyCustomObject {

    int intVal1;
    int intVal2;

    public MyCustomObject(int val1, int val2){
        intVal1 = val1;
        intVal2 = val2;
    }

    public boolean equals(Object obj){
        return (((MyCustomObject)obj).intVal1 == this.intVal1) && 
                (((MyCustomObject)obj).intVal2 == this.intVal2);
    }

    public static void main(String a[]){
        MyCustomObject m1 = new MyCustomObject(3,5);
        MyCustomObject m2 = new MyCustomObject(3,5);
        MyCustomObject m3 = new MyCustomObject(4,5);

        System.out.println(m1.equals(m2));
        System.out.println(m1.equals(m3));
    }
}

Here the output is true, false exactly the way I want it to be and I dont care of overriding the hashCode() method at all. 这里输出是真的,完全按照我想要的方式错误,我根本不关心覆盖hashCode()方法。 This means that hashCode() overriding is an option rather being a mandatory one as everyone says. 这意味着hashCode()覆盖是一个选项而不是每个人都说的强制选项。

I want a second confirmation. 我想要第二次确认。

It works for you because your code does not use any functionality (HashMap, HashTable) which needs the hashCode() API . 它适用于您,因为您的代码不使用需要hashCode() API的任何功能(HashMap,HashTable)

However, you don't know whether your class (presumably not written as a one-off) will be later called in a code that does indeed use its objects as hash key, in which case things will be affected. 但是,您不知道您的类(可能不是一次性写入)将在稍后使用其对象作为哈希键的代码中调用,在这种情况下,事情将受到影响。

As per the documentation for Object class : 根据Object类文档

The general contract of hashCode is: hashCode的一般契约是:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. 每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象的equals比较中使用的信息。 This integer need not remain consistent from one execution of an application to another execution of the same application. 从应用程序的一次执行到同一应用程序的另一次执行,该整数不需要保持一致。

  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result . 如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果

Because HashMap/Hashtable will lookup object by hashCode() first. 因为HashMap / Hashtable将首先通过hashCode()查找对象。

If they are not the same, hashmap will assert object are not the same and return not exists in the map. 如果它们不相同,则hashmap将断言对象不相同并且返回不存在于地图中。

The reason why you need to @Override neither or both, is because of the way they interrelate with the rest of the API. 您之所以不需要@Override ,是因为它们与API的其余部分相互关联。

You'll find that if you put m1 into a HashSet<MyCustomObject> , then it doesn't contains(m2) . 您会发现如果将m1放入HashSet<MyCustomObject> ,则它不contains(m2) This is inconsistent behavior and can cause a lot of bugs and chaos. 这是不一致的行为 ,可能会导致很多错误和混乱。

The Java library has tons of functionalities. Java库具有大量功能。 In order to make them work for you, you need to play by the rules, and making sure that equals and hashCode are consistent is one of the most important ones. 为了使它们适合你,你需要遵守规则,并确保equalshashCode是一致的是最重要的一个。

Most of the other comments already gave you the answer: you need to do it because there are collections (ie: HashSet, HashMap) that uses hashCode as an optimization to "index" object instances, an those optimizations expects that if: a.equals(b) ==> a.hashCode() == b.hashCode() (NOTE that the inverse doesn't hold). 大多数其他评论已经给你答案:你需要这样做,因为有一些集合(即:HashSet,HashMap)使用hashCode作为“索引”对象实例的优化,这些优化期望如果: a.equals(b) ==> a.hashCode() == b.hashCode() (注意反转不成立)。

But as an additional information you can do this exercise: 但作为附加信息,您可以执行此练习:

class Box {
     private String value;
     /* some boring setters and getters for value */
     public int hashCode() { return value.hashCode(); }
     public boolean equals(Object obj) { 
           if (obj != null && getClass().equals(obj.getClass()) { 
               return ((Box) obj).value.equals(value); 
            } else { return false; }
     }
}

The do this: 这样做:

Set<Box> s = new HashSet<Box>();
Box b = new Box();
b.setValue("hello");
s.add(b);
s.contains(b); // TRUE
b.setValue("other");
s.contains(b); // FALSE
s.iterator().next() == b // TRUE!!! b is in s but contains(b) returns false

What you learn from this example is that implementing equals or hashCode with properties that can be changed (mutable) is a really bad idea. 你从这个例子中学到的是,使用可以改变的属性(可变)实现equalshashCode是一个非常糟糕的主意。

It is primarily important when searching for an object using its hashCode() value in a collection (ie HashMap, HashSet, etc.). 在使用集合中的hashCode()值(即HashMap,HashSet等)搜索对象时,这一点非常重要。 Each object returns a different hashCode() value therefore you must override this method to consistently generate a hashCode value based on the state of the object to help the Collections algorithm locate values on the hash table. 每个对象都返回一个不同的hashCode()值,因此您必须覆盖此方法,以便根据对象的状态始终生成hashCode值,以帮助Collections算法在哈希表上定位值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM