当我覆盖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()覆盖是一个选项而不是每个人都说的强制选项。

我想要第二次确认。

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

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

根据Object类的文档 :

hashCode的一般契约是:

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

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

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

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

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

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

Java库具有大量function。 为了使它们适合你,你需要遵守规则,并确保equalshashCode是一致的是最重要的一个。

大多数其他评论已经给出了答案:你需要这样做,因为有一些集合(即:HashSet,HashMap)使用hashCode作为“索引”对象实例的优化,这些优化期望如果: a.equals(b) ==> 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 s = new HashSet(); 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是一个非常糟糕的主意。

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