Hashcode 和 equals 方法契约

Hashcode and equals methods contract

我知道当我们覆盖 equals() 方法时,我们也需要覆盖 hashcode() 以及其他方式。

但我不明白为什么我们必须这样做?

Joshua Bloch Book中明确写明我们必须这样做,因为当我们处理基于散列的集合时,它是满足 Hashcode contract 至关重要,我承认这一点,但如果我不处理基于哈希的集合怎么办?

为什么还需要它?

因为这就是它的本意:

Whenever a.equals(b), then a.hashCode() must be same as b.hashCode().

What issues should be considered when overriding equals and hashCode in Java?

有些用例你不需要 hashcode(),大部分是你自己写的场景,但你永远无法确定,因为实现可以而且可能也依赖于 hashcode() 如果他们正在使用 equals()

数据结构,例如HashMap,取决于合同。

HashMap 通过使用哈希码对条目进行分桶来实现神奇的性能特性。放入地图中且具有相同 hashcode() 值的每个项目都将放入同一个桶中。这些 "collisions" 通过使用 equals() 在同一个桶内进行比较来解决。换句话说,哈希码用于确定映射中可能相等的项目的子集,并以这种方式快速消除绝大多数项目的进一步考虑。

这只适用于将相同的对象放在同一个桶中,只有当它们具有相同的哈希码时才能确保这一点。

注意:实际上,冲突的数量比上面暗示的要多得多,因为使用的桶数必然比可能的哈希码值的数量小得多。

为什么要覆盖等于?

A programmer who compares references to value objects using the equals method expects to find out whether they are logically equivalent, not whether they refer to the same object .

HashCode即将上线

Hash function which is called to produce the hashCode should return the same hash code each and every time, when function is applied on same or equal objects. In other words, two equal objects must produce same hash code consistently.

Object Class 提供的 HashCode 的实现不是基于 logical equivalency ,

所以现在如果你不覆盖 hashCode 但覆盖 equals,那么根据你的说法,2 个对象是相等的,因为它们将通过 equals() 测试,但根据 Java 他们不是。

后果:

  1. Set 开始允许重复!!!
  2. Map#get(key) 不会 return 正确的值!!
  3. 等等许多其他后果......

根据约书亚布洛赫的书;

A common source of bugs is the failure to override the hashCode method. You must override hashCode in every class that overrides equals. Failure to do so will result in a violation of the general contract for Object.hashCode, which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable.

在覆盖 equals 时未能覆盖 hashcode 违反了 Object.hashCode 的约定。但是,如果您仅在非基于散列的集合上使用您的对象,这将不会产生影响。

但是,你是如何预防的;其他开发人员这样做。此外,如果一个对象符合集合元素的条件,最好为所有集合提供支持,不要在您的项目中有 half baked 对象。以后随时会失败,执行时会因为不关注联系人而被抓:)

这个问题在SO中已经回答了很多次,但我还是会尝试回答这个问题。

为了完全理解这个概念,我们需要理解hashcode 和 equals 的目的,它们是如何实现的,以及这个合约到底是什么(当覆盖 equals 时,哈希码也应该被覆盖)

equals方法用于判断object是否相等。对于基本类型,判断是否相等非常容易。我们可以很容易地说 int 1 总是等于 1。但是这个 equal 方法讨论的是 objects 的相等性。 object 相等性取决于实例变量或任何其他参数(完全取决于实现 - 您想要比较的方式)。

如果我们想要进行一些自定义比较,则需要覆盖此相等方法,假设我们想说如果两本书具有相同的标题和相同的作者,则它们是相同的,或者我可以说两本书是相等的,如果它们有相同的国际标准书号。

hashcode 方法 returns object 的哈希码值。 Object 哈希码 returns 的默认实现是不同的 object 的不同整数。这个整数是根据object的内存地址计算出来的。

所以我们可以说 equals 方法的默认实现只是比较哈希码来检查 object 的相等性。但是对于书本示例 - 我们需要不同的方式。

此外,相等的 object 必须生成相同的哈希码,只要它们相等即可,但是不相等的 object 不需要生成不同的哈希码 .

如果不使用基于散列的 collection,您可以违反合同并且不需要重写散列码方法 - 因为您不会在任何地方使用默认实现,但我仍然会 不建议,并且会说拥有它,因为将来当你把这些东西放在collection

中时可能需要它