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

2022-09-01 09:56:11

假设以下示例:

public record SomeRecord(int foo, byte bar, long baz)
{ }

我是否需要重写,如果我要将所述对象添加到?hashCodeequalsHashMap


答案 1

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

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

请注意,具体而言,有关实现您自己的版本的警告:

所有成员都继承自 java.lang.Record。除非在记录正文中显式重写,否则 R 已隐式声明了重写 java.lang.Record 中的 equals、hashCode 和 toString 方法的方法。

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

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


答案 2

您是否需要的答案是 - 这取决于您决定创建为.在编译或运行时也没有限制约束你这样做的形式,无论如何,类扩展总是如此。RecordObject

另一方面,该提案的主要动机之一是“低价值,重复,容易出错的代码:构造函数,访问器,equals()hashCode()toString()”。在数据载体中,这意味着在当今的Java编程中很常见。因此,进一步陈述的决定是更喜欢语义目标

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

尾巴

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

上述情况大多不能归类为编译或运行时故障,但提案本身也存在随之而来的风险:

也可以显式声明从状态说明自动派生的任何成员。但是,不小心实现访问器或等于/hashCode 可能会破坏记录的语义不变量。

(注意:后者主要是我的观点,因此消费者会想要各种灵活性,以便他们可以使用最新的功能,但在某种程度上,现有的实现曾经工作过。您会看到,在升级过程中,向后兼容性在更大程度上也很重要。


推荐