在阅读了大量的文档和文章后,我真的对equals()hashCode()方法感到非常困惑.主要是,有各种各样的例子和用法让我太困惑了.

那么,你能澄清我以下几点吗?

1.如果实体中没有任何唯一字段(id字段除外),那么我们应该使用getClass()方法还是equals()方法中只有id字段,如下所示?

@Override
public boolean equals(Object o) {
   if (this == o) return true;
   if (getClass() != o.getClass()) return false;
   
   // code omitted
}

2.如果有一个唯一键,例如private String isbn;,那么我们应该只使用这个字段吗?或者我们应该将其与getClass()结合起来,如下所示?

@Override
public boolean equals(Object o) {
   if (this == o) return true;
   if (getClass() != o.getClass()) return false;
   Book book = (Book) o;
   return isbn == book.isbn;
}

3. NaturalId个怎么样?据我所知,它用于特殊字段,例如private String isbn;.它的用途是什么?是否与equals()hashCode()方法有关?

推荐答案

getClass()

关于getClass()的用法,一切都很简单.

方法equals()需要Object类型的参数.

在执行强制转换和比较属性之前,确保您正在拨打same class的实例,这一点很重要,否则您可能会得到ClassCastException.getClass()可以用于此目的,如果对象不属于同一类,则它们显然不相等.

自然Id与代理Id

当你谈论"NaturalId"时,比如一本书的ISBN数字与"id",我猜你指的是一个持久性实体的natural key与关系数据库中使用的surrogate key.

在这一点上有不同的意见,一般建议的方法(see a link to the Hibernate user-guide and other references below)是在应用程序中使用natural id(一组独特的属性,也称为business keys)和实体在数据库中持久化only后获得的ID.

您可能会遇到基于surrogate id实现的hashCode()equals(),并进行防御性空判断以防止实体处于瞬态且其idnull的情况.根据这种实现,瞬态实体将不等于处于持久状态的实体,具有相同的属性(非空id除外).就我个人而言,我认为这种方法不正确.

以下代码示例取自最新的官方Hibernate 6.1 User-Guide

示例142.Natural Id equals/hashCode

@Entity(name = "Book")
public static class Book {

    @Id
    @GeneratedValue
    private Long id;
    private String title;
    private String author;

    @NaturalId
    private String isbn;

    //Getters and setters are omitted for brevity

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Book book = (Book) o;
        return Objects.equals(isbn, book.isbn);
    }

    @Override
    public int hashCode() {
        return Objects.hash(isbn);
    }
}

与基于代理键的实现(称为naive implementation(seeExample 139及更进一步))相比,上述使用业务键的代码在指南中表示为final approach.

Select ID vs Natural key的相同推理已在here中描述:

如果需要,则必须重写equals()和hashCode()方法

  • 打算将持久类的实例放在一个集合中(推荐用于表示多值关联的方法),并

  • 打算使用分离实例的重新附加

Hibernate保证持久标识(数据库行)的等价性

最明显的方法是通过比较

我们建议使用Business key equality实现equals()和hashCode().

有关更多信息,请参阅最近由@Vlad Mihalcea compose 的(Sep 15, 2021)篇文章,内容涉及如何使用自然键The best way to map a @NaturalId business key with JPA and Hibernate改进缓存查询结果,以及以下问题:

Java相关问答推荐

javafx getHostServices(). showDocument()调出Chrome而不是默认浏览器(Linux)

Java Streams在矩阵遍历中的性能影响

Java事件系统通用转换为有界通配符

从技术上讲,OPC UA客户端是否可以通过转发代理将请求通过 tunel 发送到OPC UA服务器?

为什么我们不能实现两个接口,其中一个接口有相同的签名,其中一个接口有默认的实现在java?'

关于泛型的覆盖规则

在Spring终结点中,是否可以同时以大写和小写形式指定枚举常量?

格式中的特定回录键-值对

GetChildren().emoveAll()不会删除 node

如何将Java文档配置为在指定的项目根目录中生成?

从映射列表中检索所有键

Quarkus:运行时出现EnumConstantNotPresentException

如何在IntelliJ IDEA的Build.sbt中添加外部JAR文件?

为什么相同的数据条码在视觉上看起来不同?

在权限列表中找不到我的应用程序

谷歌应用引擎本地服务器赢得';t在eclipse上运行

如何通过gradle命令行从build.gradle获得Java targetCompatibility

PhantomReference无法访问时会发生什么?

如何显示新布局

message.acknowledge()没有';在使用Spring Boot在ActiveMQ中读取消息后,t将消息出列