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

Java 是否需要覆盖记录的hashCode()和equals()?,java,java-14,java-record,Java,Java 14,Java Record,假设以下示例: public record SomeRecord(intfoo、字节栏、长baz) { } 如果要将所述对象添加到HashMap,是否需要覆盖hashCode和equals?否您不需要定义自己的hashCode和equals。如果希望覆盖默认实现,可以这样做 详见本规范第8.10.3节 请特别注意,关于实现您自己的版本的警告: 从java.lang.Record继承的所有成员。除非明确 在记录体中重写,R隐式声明了 重写中的equals、hashCode和toString方法

假设以下示例:

public record SomeRecord(intfoo、字节栏、长baz)
{ }

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

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

详见本规范第8.10.3节

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

从java.lang.Record继承的所有成员。除非明确 在记录体中重写,R隐式声明了 重写中的equals、hashCode和toString方法 java.lang.Record

java.lang.Record中的这些方法是否应该显式 在记录体中声明,实现应该满足 应为java.lang.Record中指定的语义

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

您是否需要它的答案实际上是-它取决于您决定创建为
记录的实体的实现。在编译或运行时,也没有任何限制来约束您这样做,而且对于扩展
Object
的类来说总是这样

头 另一方面,其中一个主要问题是“低值、重复、易出错的代码:构造函数、访问器、
equals()
hashCode()
toString()
等”。在数据载体中,这在今天的Java编程中非常常见。因此,进一步说明的决定是倾向于语义目标

…:将数据建模为数据。(如果 语义是正确的,样板将自行处理。)它 应该简单、清晰、简洁地声明肤浅不变, 表现良好的标称数据聚合

尾巴 所以,样板已经处理好了,但请注意,出于某种原因,您可能仍然希望其中一个记录组件不被视为两个不同对象之间比较过程的一部分,也就是说,您可能希望覆盖
equals
hashCode
的默认实现。此外,我对
toString
有时需要的幻想的想法是毫无疑问的,因此需要覆盖它

上述大多数情况不能归类为编译或运行时故障,但提案本身指出了它带来的风险:

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

(注意:后者主要是我的观点,因此消费者希望有各种各样的灵活性,以便他们可以使用最新的功能,但在某种程度上,现有的实现过去是有效的。你看,在升级过程中,在更大程度上也很重要。)

什么是Java记录?关于Java最常见的抱怨之一是需要编写大量代码才能创建类 有用。通常,您需要编写以下内容:

  • toString()
  • hashCode()
  • 等于()
  • 吸气剂法
  • 公共构造师
  • 对于简单的域类,这些方法通常很无聊, 重复的,和那种容易产生的东西 机械地(IDE通常提供这种功能),但到目前为止, 语言本身没有提供任何方法来实现这一点

    records的目标是扩展Java语言语法并创建 一个类是“字段,只是字段,什么都没有”的说法 但是字段。”通过你对一个类的陈述 编译器可以通过自动创建所有方法和 所有字段都参与hashCode()等方法

    对于记录中的所有属性,
    hashCode()
    equals()
    toString()
    ,这些记录都有一个默认实现

    hashCode()的默认实现。

    记录将使用记录内所有属性的哈希代码

    默认实现等于()

    记录将使用所有属性来决定两条记录是否相等

    因此,任何哈希实现,例如HashSet、LinkedHashSet、HashMap、LinkedHashMap、

    etc将使用
    hashCode()
    ,如果发生冲突,将使用
    equals()

    默认实现还是自定义实现?

    如果要使用
    hashCode()
    equals()
    中的所有属性,请不要重写

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

    这取决于您是否保留默认实现或仅为此选择一些属性

    任何内容,但如果需要自定义属性,则可以覆盖该属性以决定使用哪个属性 属性决定相等,属性决定哈希代码

    在默认实现中如何计算哈希代码?

    将使用整数和字符串的哈希代码,如下所示:

        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