重写equals而不是hashcode有什么缺点,反之亦然?

时间:2015-10-07 03:02:32

标签: java equals hashcode

我知道有很多类似的问题,但我对我读过的答案并不满意。我试图解决这个问题,但我仍然没有理解。 我所知道的是这两个在使用set或map时非常重要,尤其是HashSet,HashMap或Hash对象,它们使用哈希机制来存储元素对象。

这两种方法都用于测试两个对象是否相等。 要使两个对象A和B首先相等,它们需要具有相同的哈希值(必须在同一个桶中),然后我们必须在执行A.equals(B)时获得。

我不明白的是,为什么有必要覆盖这两种方法。 如果我们不覆盖哈希码,那该怎么办?是否必须覆盖两者。如果不是重写equals而不是hashcode的缺点,反之亦然。

2 个答案:

答案 0 :(得分:1)

正确实现hashCode对于您的对象成为基于哈希的容器中的键是必要的。其他任何事情都没有必要。

这就是为什么它对于基于散列的容器很重要,例如HashMap,HashSet,ConcurrentHashMap等。

在高级别,HashMap是一个数组,由密钥的hashCode索引,其条目是“链” - (键,值)对的列表,其中特定链中的所有键具有相同的哈希码。有关哈希表的更新,请参阅Wikipedia

考虑如果两个密钥A,B相等但具有不同的哈希代码会发生什么 - 例如,a.hashCode() == 42b.hashCode() == 37。假设你写:

hashTable.put(a, "foo");
hashTable.get(b);

由于密钥相等,您希望结果为"foo",对吧? 但是,get(b)将查看与散列37对应的链,而(a, "foo")对位于与散列42对应的链中,因此查找将失败,您将获得null

如果您打算将对象用作基于散列的容器中的键,那么重要的是等号对象具有相同的哈希码。

请注意,如果您使用非基于散列的容器(例如TreeMap),那么您不必实现hashCode,因为容器不使用它。相反,如果是TreeMap,您应该实现compareTo - 其他类型的容器可能有自己的要求。

答案 1 :(得分:0)

是的,当你重写equals方法时你也必须覆盖hashcode方法。背后的原因是,在哈希基本元素中,如果两个对象的equals方法返回true并且它们的hashcode方法返回相同的整数值,则它们是相等的。在哈希基本元素(哈希映射)中,当您对两个对象进行相等检查时,首先调用它们的哈希码方法,如果它为两者返回相同的值,则只调用equals方法。如果hashcode不为两者返回相同的值,那么它的简单性将两个对象视为不相等。默认情况下,hashcode方法返回一些随机值,因此如果通过重写equals方法使两个对象对于某些特定条件相等,它们仍然不会相等,因为它们的hashcode值不同,所以为了使它们的hascode值等于你必须覆盖它。否则,您将无法将此对象作为哈希映射的关键字。