假设以下示例:
public record SomeRecord(int foo, byte bar, long baz)
{ }
如果我要将对象添加到HashMap
中,我是否需要覆盖hashCode
和equals
方法?
假设以下示例:
public record SomeRecord(int foo, byte bar, long baz)
{ }
如果我要将对象添加到HashMap
中,我是否需要覆盖hashCode
和equals
方法?
hashCode
和equals
方法。如果你希望覆盖默认实现,可以这样做。所有从java.lang.Record继承的成员。除非在记录体中显式地进行了覆盖,否则R将隐式声明覆盖了java.lang.Record的equals、hashCode和toString方法。
如果在记录体中显式声明了来自java.lang.Record的任何这些方法,则实现应满足java.lang.Record中指定的预期语义。
特别是,自定义的equals
实现必须满足预期的语义,即记录的副本必须等于该记录。Record
如何实现 hashCode
是留给实现的细节(记住 Java 是一种语言规范)。然而在实践中,我期望实现者通常只会哈希所有成员。冲突是在集合的实现中处理的。HashMap 的 openjdk 实现具有相当复杂的处理方式,根据冲突数量改变结构。 - sprinterhashCode()
实现是return 1;
。它遵守Object.hashCode()和Record.hashCode()的契约。(有一个标志可以使System.identityHashCode(Object)始终返回1:-XX:hashCode=2
) - Johannes Kuhnequals
和hashCode
中排除记录组件。您需要自己编写方法来实现。 - sprinterRecord
的实体的实现方式。编译时或运行时都没有限制来约束您这样做,而对于扩展Object
的类来说,这一直是如此。equals()
、hashCode()
、toString()
等”。在数据载体中,这在今天的Java编程中相当常见。因此,进一步说明的决定是更喜欢语义目标。
因此,样板已经处理完毕,但请注意,您可能仍然希望其中一个记录组件不被视为在两个不同对象之间进行比较的一部分,这就是您可能想要覆盖所提供的“equals”和“hashCode”的默认实现的地方。此外,我毫不怀疑有时会需要一些...:将数据建模为数据。(如果语义正确,样板文件将自己处理)。声明浅不可变、行为良好的名义数据聚合应该是简单、清晰和简洁的。
toString
的花哨效果,因此需要对其进行重载。什么是Java Record? Java最常见的抱怨之一是,为了使类有用,需要编写大量代码。通常需要编写以下内容:
- toString()
- hashCode()
- equals()
- Getter方法
- 公共构造函数
对于简单的领域类,这些方法通常是无聊、重复的事情,很容易机械地生成(IDE经常提供此功能),但目前,语言本身没有提供任何方法来实现这一点。
记录的目标是扩展Java语言语法,创建一种方式来表明一个类是“字段,只是字段,而且仅仅是字段”。通过您对类做出这种声明,编译器可以帮助自动创建所有方法,并使所有字段参与hashCode()等方法。
记录会为记录内部的所有属性提供hashCode()
、equals()
和toString()
的默认实现
hashCode()的默认实现
记录将使用记录内部所有属性的哈希码
equals()的默认实现
记录将使用所有属性来决定两个记录是否相等
因此,任何哈希实现,例如HashSet、LinkedHashSet、HashMap、LinkedHashMap等,都将使用hashCode()
,并在发生任何冲突时使用equals()
默认实现还是自定义实现?
如果要在hashCode()
和equals()
中使用所有属性,则不需要覆盖
需要为记录覆盖hashCode()和equals()吗?
保留默认实现还是选择仅选取某些属性取决于您
任何东西,但如果您想要自定义属性,则可以覆盖以决定哪些属性决定相等性和属性生成hashCode
默认实现如何计算hashCode?
将使用整数和字符串的哈希码,如下所示:
int hashCode = 1 * 31;
hashCode = (hashCode + "a".hashCode()) & 0x7fffffff;
hashCode()
, equals()
和toString()
的默认实现。 static record Record(int id, String name) {
}
public static void main(String[] args) {
Record r1 = new Record(1, "a");
Record r2 = new Record(1, "a");
Set<Record> set = new HashSet<>();
set.add(r1);
set.add(r2);
System.out.println(set);
System.out.println("Hashcode for record1: " + r1.hashCode());
System.out.println("Hashcode for record2: " + r2.hashCode());
int hashCode = 1 * 31;
hashCode = (hashCode + "a".hashCode()) & 0x7fffffff;
System.out.println("The hashCode: " + hashCode);
}
输出
[Record[id=1, name=a]]
Hashcode for record1: 128
Hashcode for record2: 128
The hashCode: 128
, Resources:
java.lang.Record
中概述的equals()
和hashCode()
的精细语义。 - Brian Goetzrecord
这样大声呼喊“值类型”的功能具有公共构造函数,就像Integer
、Double
等的构造函数一样被标记为过时,而不是使用工厂方法允许在JRE自行决定的情况下进行共享,例如valueOf(…)
? - Holger