您是否需要为记录覆盖 hashCode() 和 equals()?
Do you need to override hashCode() and equals() for records?
假设以下示例:
public record SomeRecord(int foo, byte bar, long baz)
{ }
如果我要将所述对象添加到 HashMap
,是否需要覆盖 hashCode
和 equals
?
不,您不需要定义自己的 hashCode
和 equals
。如果您希望覆盖默认实现,您可以这样做。
有关详细信息,请参阅规范的第 8.10.3 节https://docs.oracle.com/javase/specs/jls/se14/preview/specs/records-jls.html#jls-8.10
请注意,具体来说,关于实施您自己的版本的警告:
All the members inherited from java.lang.Record. Unless explicitly
overridden in the record body, R has implicitly declared methods that
override the equals, hashCode and toString methods from
java.lang.Record.
Should any of these methods from java.lang.Record be explicitly
declared in the record body, the implementations should satisfy the
expected semantics as specified in java.lang.Record.
特别是,自定义 equals
实现必须满足记录的副本必须等于记录的预期语义。这对于 类 通常不是真的(例如,如果两个 Car
对象的 VIN
值相同,即使 owner
字段不同,它们也可能是 equals
)但是记录必须为真。此限制意味着几乎没有任何理由覆盖 equals
.
你是否需要它的答案实际上是 - 它取决于你决定创建的实体的实现作为 Record
。在编译或运行时没有限制你这样做的形式,并且 类 扩展 Object
总是如此。
头
另一方面,主要的 motivations for the proposal 之一是 "low-value, repetitive, error-prone code:constructors, accessors, equals()
, hashCode()
, toString()
etc"。在数据载体中,这在今天的 Java 编程中很常见。因此,进一步说明的决定是更喜欢语义目标
...: modeling data as data. (If the
semantics are right, the boilerplate will take care of itself.) It
should be easy, clear, and concise to declare shallowly-immutable,
well-behaved nominal data aggregates.
尾巴
因此,样板文件已处理完毕,但请注意,出于某种原因,您可能仍希望不将其中一个记录组件视为两个不同 objects 之间比较过程的一部分这就是您可能想要 覆盖 提供的 equals
和 hashCode
的默认实现的地方。此外,毫无疑问,我对 toString
有时需要的奇思妙想的想法毫无疑问,因此也需要 覆盖 它。
以上大部分不能归类为编译或运行时失败,但提案本身阅读了它带来的风险:
Any of the members that are automatically derived from the state
description can also be declared explicitly. However, carelessly
implementing accessors or equals/hashCode risks undermining the
semantic invariants of records.
(注意:后者主要是我的意见,这样消费者会希望获得各种灵活性,以便他们可以使用最新的功能,但在某种程度上,现有的实现曾经工作。你看,backward compatibility 在升级过程中也更重要。)
What Is a Java Record? One of the most common complaints about Java is that you need to write a lot of code for a class to be
useful. Quite often you need to write the following:
- toString()
- hashCode()
- equals()
- Getter methods
- A public constructor
For simple domain classes, these methods are usually boring,
repetitive, and the kind of thing that could easily be generated
mechanically (and IDEs often provide this capability), but as of now,
the language itself doesn’t provide any way to do this.
The goal of records is to extend the Java language syntax and create a
way to say that a class is “the fields, just the fields, and nothing
but the fields.” By you making that statement about a class, the
compiler can help by creating all the methods automatically and having
all the fields participate in methods such as hashCode().
记录附带 记录内所有属性的 hashCode()
、equals()
和 toString()
默认实现
hashCode()的默认实现
记录将使用记录内所有属性的哈希码
默认实现equals()
记录将使用所有属性来决定两条记录是否相等
所以任何哈希实现,例如HashSet,LinkedHashSet,HashMap,LinkedHashMap,
etc 将使用 hashCode()
,如果发生任何碰撞,将使用 equals()
默认实现还是自定义实现?
如果您想使用 hashCode()
和 equals()
中的所有属性,则不要覆盖
是否需要覆盖记录的 hashCode() 和 equals()?
由您决定是保留默认实现还是 select 只保留一些属性
任何东西,但如果你想要自定义属性,你可以覆盖来决定哪个
属性决定相等性,属性决定 hashCode
hashCode在默认实现中是如何计算的?
将像这样使用整数和字符串的哈希码:
int hashCode = 1 * 31;
hashCode = (hashCode + "a".hashCode()) & 0x7fffffff;
,下面的代码带有 默认实现 for hashCode()
,equals()
和toString()
.
HashSet没有将这两条相加,因为这两条记录的hashCode相同且等于
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
,资源:
假设以下示例:
public record SomeRecord(int foo, byte bar, long baz)
{ }
如果我要将所述对象添加到 HashMap
,是否需要覆盖 hashCode
和 equals
?
不,您不需要定义自己的 hashCode
和 equals
。如果您希望覆盖默认实现,您可以这样做。
有关详细信息,请参阅规范的第 8.10.3 节https://docs.oracle.com/javase/specs/jls/se14/preview/specs/records-jls.html#jls-8.10
请注意,具体来说,关于实施您自己的版本的警告:
All the members inherited from java.lang.Record. Unless explicitly overridden in the record body, R has implicitly declared methods that override the equals, hashCode and toString methods from java.lang.Record.
Should any of these methods from java.lang.Record be explicitly declared in the record body, the implementations should satisfy the expected semantics as specified in java.lang.Record.
特别是,自定义 equals
实现必须满足记录的副本必须等于记录的预期语义。这对于 类 通常不是真的(例如,如果两个 Car
对象的 VIN
值相同,即使 owner
字段不同,它们也可能是 equals
)但是记录必须为真。此限制意味着几乎没有任何理由覆盖 equals
.
你是否需要它的答案实际上是 - 它取决于你决定创建的实体的实现作为 Record
。在编译或运行时没有限制你这样做的形式,并且 类 扩展 Object
总是如此。
头
另一方面,主要的 motivations for the proposal 之一是 "low-value, repetitive, error-prone code:constructors, accessors, equals()
, hashCode()
, toString()
etc"。在数据载体中,这在今天的 Java 编程中很常见。因此,进一步说明的决定是更喜欢语义目标
...: modeling data as data. (If the semantics are right, the boilerplate will take care of itself.) It should be easy, clear, and concise to declare shallowly-immutable, well-behaved nominal data aggregates.
尾巴
因此,样板文件已处理完毕,但请注意,出于某种原因,您可能仍希望不将其中一个记录组件视为两个不同 objects 之间比较过程的一部分这就是您可能想要 覆盖 提供的 equals
和 hashCode
的默认实现的地方。此外,毫无疑问,我对 toString
有时需要的奇思妙想的想法毫无疑问,因此也需要 覆盖 它。
以上大部分不能归类为编译或运行时失败,但提案本身阅读了它带来的风险:
Any of the members that are automatically derived from the state description can also be declared explicitly. However, carelessly implementing accessors or equals/hashCode risks undermining the semantic invariants of records.
(注意:后者主要是我的意见,这样消费者会希望获得各种灵活性,以便他们可以使用最新的功能,但在某种程度上,现有的实现曾经工作。你看,backward compatibility 在升级过程中也更重要。)
What Is a Java Record? One of the most common complaints about Java is that you need to write a lot of code for a class to be useful. Quite often you need to write the following:
- toString()
- hashCode()
- equals()
- Getter methods
- A public constructor
For simple domain classes, these methods are usually boring, repetitive, and the kind of thing that could easily be generated mechanically (and IDEs often provide this capability), but as of now, the language itself doesn’t provide any way to do this.
The goal of records is to extend the Java language syntax and create a way to say that a class is “the fields, just the fields, and nothing but the fields.” By you making that statement about a class, the compiler can help by creating all the methods automatically and having all the fields participate in methods such as hashCode().
记录附带 记录内所有属性的 hashCode()
、equals()
和 toString()
默认实现
hashCode()的默认实现
记录将使用记录内所有属性的哈希码
默认实现equals()
记录将使用所有属性来决定两条记录是否相等
所以任何哈希实现,例如HashSet,LinkedHashSet,HashMap,LinkedHashMap,
etc 将使用 hashCode()
,如果发生任何碰撞,将使用 equals()
默认实现还是自定义实现?
如果您想使用 hashCode()
和 equals()
中的所有属性,则不要覆盖
是否需要覆盖记录的 hashCode() 和 equals()?
由您决定是保留默认实现还是 select 只保留一些属性
任何东西,但如果你想要自定义属性,你可以覆盖来决定哪个 属性决定相等性,属性决定 hashCode
hashCode在默认实现中是如何计算的?
将像这样使用整数和字符串的哈希码:
int hashCode = 1 * 31;
hashCode = (hashCode + "a".hashCode()) & 0x7fffffff;
,下面的代码带有 默认实现 for hashCode()
,equals()
和toString()
.
HashSet没有将这两条相加,因为这两条记录的hashCode相同且等于
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
,资源: