小编典典

如何在不冒失去对称性的风险的情况下实现与休眠相等?

hibernate

阅读完(再次,应该很久以前就应该这样做)正确地实现equals和hashcode之后,我得出以下结论,这对我有用:

如果是JDK 7之前的版本 :建议使用Apache Commons
equalsbuilder和hashcodebuilder。(或番石榴)。他们的javadocs包含如何正确使用它们的示例。

如果是JDK 7 ++ :使用新的Objects实用程序类

但是,如果编写用于hibernate的 代码,则会出现一些特殊要求(请参阅更深层的资料),其中有一些建议的用法是使用 instanceof 而不是
getClass ,这是因为hibernate模式创建了延迟加载的子类的代理。

但据我了解,如果这样做,则会出现另一个潜在问题:使用getClass的原因是为了确保equals合同的对称属性。JavaDocs:

*It is symmetric: for any non-null reference values x and y, x.equals(y) 
 should return true if and only if y.equals(x) returns true.*

并且通过使用instanceof,可能不对称。示例:B扩展了A。A的equals进行A的检查实例。B的equals进行B的检查实例。给A a和B b:

a.equals(b)-> true b.equals(a)-> false

如何在不冒失去对称性的风险的情况下实现与hibernate相等?看来使用getClass时不安全,使用instanceof时也不安全?

答案是从不向子类中添加重要成员,然后再安全地使用instanceof(对于处于hibernate状态的人)吗?

我阅读的资料:

在Java中重写equals和hashCode时应考虑哪些问题?

Josh Blochs优秀著作“ Effective
Java”中的项目7和8,http:
//web.archive.org/web/20110622072109/http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf

关于Java 7:http//www.javacodegeeks.com/2012/11/guavas-
objects-class-equals-hashcode-and-
tostring.html


阅读 274

收藏
2020-06-20

共1个答案

小编典典

在提出更多建议后,我总结了以下问题:

  • 使用instanceof,就永远不能向子类中添加重要的成员。(在保留等价合约的同时,无法扩展可实例化的类并添加值组件(Bloch)
  • 使用getClass会违反Liskov替换原则

朗格说http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals.html

* test的instanceof测试仅对最终类是正确的,或者至少在父类中equals()方法是最终的。后者实质上意味着没有子类必须扩展超类的状态,而只能添加与对象的状态和行为无关的功能或字段,例如瞬态或静态字段。

另一方面,使用getClass()测试的实现始终符合equals()合同;他们是正确和强大的。但是,它们在语义上与使用instanceof
test的实现有很大不同。使用getClass()的实现不允许将子类与超类对象进行比较,即使子类未添加任何字段并且甚至不希望覆盖equals()也不行。这种“琐碎”的类扩展例如是在为该“琐碎”目的而定义的子类中添加了调试打印方法。如果超类禁止通过getClass()检查进行混合类型比较,那么普通扩展将无法与其超类进行比较。

总结-将instanceof与final for equals一起使用可避免破坏对称性,并避免hibernate的“代理”问题。

2020-06-20