hashCode()只应使用equals()中使用的不可变字段的子集吗?

ary*_*vie 5 java overriding equals hashcode contract

情况

我需要覆盖equals(),因为我建议我也hashCode()使用相同的字段覆盖该方法.然后,当我看着一个只包含一个对象的集合时,我得到了令人沮丧的结果

set.contains(object)
=> false
Run Code Online (Sandbox Code Playgroud)

set.stream().findFirst().get().equals(object)
=> true
Run Code Online (Sandbox Code Playgroud)

我现在明白了,这是由于object在添加后set再次更改其hashCode 所做的更改.contains然后查看错误的密钥,找不到object.

我对实施的要求是

  • 需要可变字段才能正确实现 equals()
  • 即使它们容易发生变化,也可以安全地使用这些对象基于散列CollectionsMaps灰尘HashSet.

这违反了惯例

是否存在使用仅用于equals()计算hashCode()而不是全部使用的字段子集的危险?

更具体而言,这将意味着:equals()使用大量的物体的领域的,而hashCode()仅使用在所使用的那些字段equals()和是不可变的.

我认为这应该没问题,因为

  • 合同是fullfilled:相等的对象会产生相同的hashCode,而相同的hashCode并不necesairly意味着对象是相同的.
  • 即使对象暴露于更改,对象的hashCode也保持不变,因此可以HashSet在这些更改之前和之后找到.

相关帖子帮助我理解了我的问题,但没有解决方法:在Java中覆盖equals和hashCode时应该考虑哪些问题?equals和hashcode的不同字段

小智 0

契约确实会履行。合同规定.equal()对象必须始终相同.hashCode()。相反的情况不一定是真的,我想知道一些人和 IDE 是否痴迷于应用这种实践。如果这对于所有可能的组合都是可能的,那么您就会发现完美的哈希函数。

顺便说一句,IntelliJ 在生成 hashCode 和 equals 时提供了一个很好的向导,通过单独处理这两种方法并允许区分您的选择。显然,相反,即在 中提供更多字段hashCode()而在 中提供更少字段equals()将违反合同。