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

时间:2010-04-25 07:53:34

标签: java equals hashcode

好的,我从许多地方和消息来源得知,每当我覆盖equals()方法时,我都需要覆盖hashCode()方法。但请考虑以下代码

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));
    }
}

这里的输出是真的,完全按照我想要的方式假,我根本不关心覆盖hashCode()方法。这意味着hashCode()覆盖是一个选项,而不是每个人都说的强制选项。

我想要第二次确认。

5 个答案:

答案 0 :(得分:32)

它适用于您,因为您的代码不使用需要hashCode() API 的任何功能(HashMap,HashTable)。

但是,您不知道您的类(可能不是一次性写入)稍后会在确实使用其对象作为哈希键的代码中调用,在这种情况下,事情会受到影响。

根据documentation for Object class

  

hashCode的一般合约是:

     
      
  • 每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象上的equals比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,此整数不需要保持一致。

  •   
  • 如果两个对象根据equals(Object)方法相等,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果

  •   

答案 1 :(得分:11)

因为HashMap / Hashtable将首先通过hashCode()查找对象。

如果它们不相同,则hashmap将断言对象不相同并且返回不存在于地图中。

答案 2 :(得分:5)

您之所以不需要@Override的原因,是因为它们与API的其他部分相互关联。

您会发现,如果您将m1放入HashSet<MyCustomObject>,那么它就不会contains(m2)。这是不一致的行为,可能会导致很多错误和混乱。

Java库具有大量功能。为了让它们而工作,您需要遵守规则,并确保equalshashCode一致是最重要的一个。< / p>

答案 3 :(得分:4)

大多数其他评论已经给出了答案:你需要这样做,因为有一些集合(即:HashSet,HashMap)使用hashCode作为“索引”对象实例的优化,这些优化期望如果: a.equals(b) ==&gt; a.hashCode() == b.hashCode()(注意反之不成立。)

但作为附加信息,您可以执行此练习:

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; }
     }
}

这样做:

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

您从这个示例中学到的是,实现equalshashCode具有可以更改的属性(可变)是一个非常糟糕的主意。

答案 4 :(得分:0)

在使用集合中的hashCode()值(即HashMap,HashSet等)搜索对象时,这一点非常重要。每个对象都返回一个不同的hashCode()值,因此您必须覆盖此方法,以便根据对象的状态一致地生成hashCode值,以帮助Collections算法在哈希表上找到值。