将超类合并到Guava Objects.hashcode()实现的正确方式是什么?

22

也许这是个愚蠢的问题,但我不想搞砸了。假设我有两个Java类:Class1Class2,其中Class2 extends Class1。我想要用Guava重写这两个类的Object.hashcode()方法。对于超类,我已经有了

@Override
public int hashCode() {
    return Objects.hashcode(mField1, mField2);
}

对于Class2,如何正确实现考虑了Class1成员的hashcode()函数?是像这样实现吗?

@Override
public int hashcode() {
    return Objects.hashcode(super.hashcode(), mField3, mField4);
}  

我感觉是对的,但我需要一些验证。Joshua Bloch在《Effective Java》中没有涉及这种情况,Guava文档也没有。


如果Class2实例的相等性也取决于Class1的字段,那么这是一个完全合理的实现——不依赖于super.hashCode()将是一个错误(具体来说是性能上的问题)。 - Dimitris Andreou
非常好的答案和讨论,感谢大家。在我的情况下,我不需要测试Class1和Class2实例之间的相等性,但下面提出的观点值得了解和理解。 - Andy Dennie
3个回答

13

是的,那看起来是正确的。如果你使用Objects.hashCode(f1, f2, f3, f4),效果也是一样的。如果你查看其实现,会发现类似result += 31 * result + hashcodeOfCurrentObject的表达式。这意味着你的结果将是31加上超级哈希码,虽然不是完全相同,但不会有问题。


10

《Effective Java》确实解决了这个问题...它说你不应该这样做。条款8:

事实证明,这是面向对象语言中等价关系的一个根本性问题。除非你愿意放弃面向对象抽象的好处,否则无法扩展可实例化的类并添加值组件同时保持equals合同。

(推论:相同的理由适用于hashCode()。)


不,hashCode()不是二元关系,因此它不需要“对称”,这是使等于()在层次结构中出错的属性。我在问题中没有看到任何暗示Class1的实例可以等于Class2的实例,这正是E.J.所覆盖的问题。 - Dimitris Andreou
从问题中无法确定具体情况,因此我想至少尝试涵盖这种情况。 - Louis Wasserman
2
但为了更清晰地表达:如果 x.equals(y),那么 x.hashCode() 有合约义务等于 y.hashCode()。如果我们希望 Class1 的实例等于 Class2 的实例,那么它们的 hashCode() 实现也需要一致,至少在不同类的实例相等的情况下如此。 - Louis Wasserman
如果你不确定问题,那你怎么确定答案呢? :-) 我猜你可以通过添加一些类似于“只有在你的hashCode()出现问题时,以下答案才适用于equals()”这样的内容来澄清。 - Dimitris Andreou
2
点赞,因为尽管这些评论中存在一些担忧,但在大多数情况下,人们会同时覆盖equalshashcode,因此这一点非常重要。 - bacar
1
在其他情况下,当人们重写 hashCode 但没有重写 equals(或者重写了 equals 但没有重写 hashCode)时,他们正在做一些不好的事情。甚至可以说是不道德的。 - Piotr Findeisen

0
尽管 Bozho 的建议是有效的,但我更喜欢这种方法:
@Override
public int hashCode() {
    return Objects.hashcode(mField1, getParentField1(), getParentField2());
}

2
但是,如果父类的哈希码计算发生更改,则子类的哈希码不会反映出这种变化。另外,超类哈希码可能使用一些子类无法访问的私有字段。 - ColinD
@ColinD 我知道。只有在您了解并可以访问超类的情况下,此版本才有意义。 - Sean Patrick Floyd
我不确定这种方法有什么好处,你能解释一下为什么你更喜欢它吗?缺点似乎是子类现在必须跟踪超类的字段,这在维护方面可能会有些麻烦。 - Andy Dennie
1
@AndyD 请查看Louis Wasserman的回答:每个类都应该对自己的契约负责。 - Sean Patrick Floyd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接