您是否需要覆盖记录的 hashCode() 和 equals() ?

sha*_*vit 20 java java-14 java-record

假设以下示例:

public record SomeRecord(int foo, byte bar, long baz)
{ }
Run Code Online (Sandbox Code Playgroud)

我是否需要覆盖hashCode,equals如果我要将所述对象添加到 a 中HashMap?

spr*_*ter 19

不,您不需要定义自己的hashCode和equals. 如果您希望覆盖默认实现,您可以这样做。

有关详细信息,请参阅规范的第 8.10.3 节https://docs.oracle.com/javase/specs/jls/se14/preview/specs/records-jls.html#jls-8.10

请特别注意,关于实现您自己的这些版本的警告:

继承自 java.lang.Record 的所有成员。除非在记录主体中明确覆盖,R 已经隐式声明了覆盖 java.lang.Record 中的 equals、hashCode 和 toString 方法的方法。

如果 java.lang.Record 中的任何这些方法在记录主体中显式声明,则实现应满足 java.lang.Record 中指定的预期语义。

特别是,自定义equals实现必须满足记录的副本必须等于记录的预期语义。这对于类通常不是真的(例如,即使字段不同,两个Car对象也可能是equals它们的VIN值相同owner),但对于记录必须是真的。这种限制意味着很少有任何理由覆盖equals.

  • 它计算所有记录组件的 hashCode。 (2认同)
  • `hashCode()` 的一个有效(但愚蠢)的实现是 `return 1;`。它遵守 Object.hashCode() 和 Record.hashCode() 的约定。(有一个标志使 System.identityHashCode(Object) 始终返回 1:`-XX:hashCode=2`) (2认同)

Nam*_*man 5

您是否需要它的答案实际上是 -这取决于您决定创建为Record. 在编译或运行时没有任何限制来约束您这样做,并且Object无论如何扩展类一直都是这种情况。

头

在另一方面中,初级中的一个为提案动机一直是“低价值的,重复的,容易出错的代码:构造,访问者equals(),hashCode(),toString()等等”。在数据载体中,这在当今的 Java 编程中很常见。因此,进一步陈述的决定是更喜欢语义目标和

...:将数据建模为数据。(如果语义是正确的,样板会自行处理。)声明浅不可变的、行为良好的名义数据聚合应该是简单、清晰和简洁的。

尾巴

因此,样板已得到处理,但请注意,出于某种原因,您可能仍然希望您的记录组件之一不被视为两个不同对象之间比较过程的一部分,而这正是您可能想要覆盖的地方equals和hashCode提供的默认实现。此外,毫无疑问,我认为有时需要 a 的幻想,toString因此也需要覆盖它。

以上大多不能归类为编译或运行时失败,但提案本身读取了随之而来的风险:

任何从状态描述自动派生的成员也可以显式声明。然而,粗心地实现访问器或 equals/hashCode 可能会破坏记录的语义不变量。

(注意:后者主要是我的意见,这样消费者会希望获得各种灵活性,以便他们可以使用最新的功能,但在某种程度上,现有的实现曾经可以工作。你看,向后兼容性在更大程度上很重要,因为在升级过程中很好。)