8

“为什么 Sun/Oracle 的人每次都强迫我们同时覆盖 equals() 和 hashCode()?”

每个人都知道,如果你覆盖一个对象的 equals() 或 hashCode(),你也必须覆盖另一个,因为这两者之间有一个契约:

请注意,每当重写此方法 [即 equals()] 时,通常都需要重写 hashCode 方法,以维护 hashCode 方法的一般约定,即相等的对象必须具有相等的哈希码。-- Object.equals() 的 API 文档

为什么它不在 Object 类中以这种方式实现:

public boolean equals(Object obj) {
    return this.hashCode() == obj.hashCode()
}

如果他们这样做,它将使世界其他地区免于实施这两种方法。只覆盖 hashCode() 就足够了。

我想这些家伙有充分的理由不这样做。我只是看不到它-请为我解决这个问题。

4

3 回答 3

12

如果a.equals(b)返回 true,则a.hashCode() == b.hashCode()必须评估为true

反之则不然!拥有两个a.hashCode() == b.hashCode()为真但a.equals(b)为假的对象是完全有效的。

事实上,这是必要的。有 2 32 个可能的返回值hashCode()。在任何给定时刻,JVM 都可以容纳超过2 32 个对象(假设有足够的内存,这在当今是很有可能的)。假设没有一个对象彼此相等(很容易做到,只要让它们成为"s1", "s2", ...),那么您肯定会遇到校验和的冲突(请参阅Pidgeonhole 原理)。

事实上,这是最简单的可能hashCode实现,对于每个类*都是正确的(但在其他方面非常糟糕):

public int hashCode() {
  return 0;
}

它神奇地满足了总hashCode()合同的所有要求。

* 除了那些具有hashCode必须实现的已定义和记录的算法的类,主要示例是String.hashCode().

于 2013-08-26T14:08:47.893 回答
3

Joachim 是正确的,但还有另一个原因:效率。

equals()计算哈希码可能很昂贵,如果被调用,这种工作将是不必要的,但hashCode()从来没有。

有很多情况会出现这种情况。只有类Hashtable(或使用它的类)调用hashCode().

于 2013-08-26T14:17:41.957 回答
1

有无限数量的对象具有相同的 hashcOde。这意味着您不能单独比较 hashCde。

一个简单的例子是Long.hashCode():每个Long是 的倍数的值1L << 32 + 1都有一个 hashCode 0

于 2013-08-26T14:14:17.213 回答