当前位置: 首页 > 面试题库 >

Java The JPA hashCode() / equals() dilemma

茅星雨
2023-03-14
问题内容

这里已经有一些 关于JPA实体的讨论,以及对于JPA实体类应该使用哪种hashCode()/ equals()实现。它们中的大多数(如果不是全部)都依赖于Hibernate,但是我想中立地讨论它们(通过顺便说一下,我正在使用EclipseLink)。

在以下方面,所有可能的实现都有各自的优点和缺点:

hashCode()/equals()合同一致性(不变性)为List/ Set操作
是否可以检测到相同的对象(例如,来自不同的会话,来自延迟加载的数据结构的动态代理)
实体在分离(或非持久)状态下是否行为正确
据我所知,有三种选择:

  1. 不要覆盖它们;依靠Object.equals()Object.hashCode()
  2. hashCode()/ equals()工作
  3. 无法识别相同的对象,动态代理问题
  4. 独立实体没有问题
  5. 根据主键覆盖它们
  6. hashCode()/ equals()坏了
  7. 正确的身份(对于所有管理实体)
  8. 独立实体的问题
  9. 根据Business-Id(非主键字段;外键如何?) 覆盖它们
  10. hashCode()/ equals()坏了
  11. 正确的身份(对于所有管理实体)
  12. 独立实体没有问题

我的问题是:

  1. 我错过了一个选项和/或优点/缺点吗?
  2. 你选择了什么选项,为什么?

更新1:

通过“ hashCode()/ equals()被破坏”,我的意思是连续hashCode()调用可能会返回不同的值,也就是(当正确实施)不在的感觉打破ObjectAPI文档,但是当试图从检索改变实体引起的问题Map, Set或其他基于哈希Collection。因此,在某些情况下,JPA实现(至少是EclipseLink)将无法正常工作。

更新2:

谢谢你的回答-大多数都具有卓越的质量。
不幸的是,我仍然不确定哪种方法最适合实际应用程序,或者如何确定适合我的应用程序的最佳方法。因此,我将保持开放的态度,并希望有更多的讨论和/或意见。


问题答案:

个人已经在不同的项目中使用了这三种策略。我必须说,在我看来,选项1在现实生活中是最可行的。以我的经验,破坏hashCode()/ equals()一致性会导致许多疯狂的错误,因为每次将最终结果添加到集合中之后,相等性的结果都会改变。

但是,还有其他选择(也各有利弊):

a)基于一组不可变的,非null,分配的构造函数,字段的hashCode /等于

(+)所有三个条件均得到保证

(-)字段值必须可用于创建新实例

(-)如果必须更改其中之一,会使处理变得复杂

b)基于由应用程序(在构造函数中)而不是JPA分配的主键的hashCode /等于

(+)所有三个条件均得到保证

(-)你无法利用DB序列之类的简单可靠的ID生成状态

(-)如果在分布式环境(客户端/服务器)或应用程序服务器群集中创建新实体,则会很复杂

c)基于实体构造函数分配的UUID的 hashCode /等于

(+)所有三个条件均得到保证

(-)UUID生成的开销

(-)可能会使用两次相同的UUID,这有一点风险,具体取决于所使用的算法(可由数据库上的唯一索引检测到)



 类似资料:
  • 比较两个相等的日期。 当且仅当参数不为null并且是一个Date对象时,结果才为真,该对象表示与此对象相同的时间点,以毫秒为单位。 因此,当且仅当getTime方法为两者返回相同的long值时,两个Date对象才相等。 语法 (Syntax) public boolean equals(Object obj) 参数 (Parameters) obj - 要与之比较的对象。 返回值 (Return

  • 该方法确定调用方法的Number对象是否等于作为参数传递的对象。 语法 (Syntax) public boolean equals(Object o) 参数 (Parameters) o - 任何对象。 返回值 (Return Value) 如果参数不为null并且是相同类型且具有相同数值的对象,则方法返回True。 例子 (Example) 以下是此方法的使用示例 - class Examp

  • 描述 (Description) 该方法确定调用方法的Number对象是否等于作为参数传递的对象。 语法 (Syntax) public boolean equals(Object o) 参数 (Parameters) 这是参数的细节 - Any object. 返回值 (Return Value) 如果参数不为null并且是相同类型且具有相同数值的对象,则该方法返回True。 Java API

  • Compare this to another sequence for equality. Signature Sequence.equals = function(other, equalityFn) { /*...*/ } Sequence.equals = function equals(other, equalityFn) { if (!(other instanceof Seque

  • 问题内容: 如果我为一个类实现,是否仍然需要重写该方法?还是会为之工作? 如果答案为 否 ,那么如果出现差异怎么办?比方说,我的方式长期两个对象作为内享有平等的方法是从我的方式长期在同一类的两个对象为内平等不同的。 而且,如果我实施了,是否还必须重写? 问题答案: 虽然建议(并且非常明智)暗示它(反之亦然),但这 不是 必需的。旨在在对一系列对象执行排序时使用,而仅测试直接相等性。 该链接提供了一

  • 问题内容: 输出是 只是对.equals有一个简单的问题。 不管对象内容如何,仅当两个对象引用都指向同一对象时才返回true吗? 编辑 :现在我了解有关的部分,但是为什么2号线和3号线也不会返回? 编辑 :我相信看参考变量的地址,因此s1和s2不能相等。如果我的假设不正确,请纠正我 问题答案: 是,,这意味着两个对象引用不同,结果为false。 对于,您可以使用 为了进行编辑,您要在两个不同的St

  • 问题内容: and方法必须一致,这意味着当两个对象根据方法相等时,它们的方法应返回相同的哈希值。 如果我们不重写hashCode()方法,则Java将返回唯一的哈希码。 为什么取消注释该行会导致编译错误? 如果对象的哈希码不相等,即使默认哈希码有所不同,为什么它们显示为相等? 问题答案: 平等仅由方法equals()确定。并且hashCode()方法可用于其他情况,例如Map或Set。实际调用eq

  • 问题内容: 使用SQL时,在子句中使用而不是有什么好处? 没有任何特殊的运营商,并且是相同的,对不对? 问题答案: 并且是不同的运算符。这里的大多数答案都集中在通配符支持上,这不是这些运算符之间的唯一区别! 是对数字和字符串进行运算的比较运算符。比较字符串时,比较运算符将比较 整个字符串 。 是一个字符串运算符,它 逐个字符地 比较。 使事情复杂化的是,两个运算符都使用排序规则,该排序规则可能对比