如何实现等于休眠而不会冒失去对称性的风险? [英] How to implement equals with hibernate without risking losing the symmetric property?

查看:144
本文介绍了如何实现等于休眠而不会冒失去对称性的风险?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在读完之后(再一次,应该在很久以前这样做了)实现equals和hashcode正确我得出这些结论, 如果预JDK 7 :更喜欢使用Apache commons equalsbuilder和hashcodebuilder。 (或番石榴)。
他们的javadoc包含了如何以良好方式使用它们的例子。



如果JDK 7 ++ :使用新的对象实用程序class

但是,如果为hibernate编写,会出现一些特殊条件(请参阅更深层次的源代码)
其中,推荐使用 instanceof 而不是 getClass ,这是由于hibernate创建了延迟加载的子类的代理。



理解,如果这样做会发生另一个潜在的问题:使用getClass的原因是为了确保等于合约的对称性。 JavaDocs:

  *它是对称的:对于任何非空引用值x和y,x.equals(y)
应当返回true当且仅当y.equals(x)返回true。*

使用instanceof,可能不是对称的。
示例:B扩展A. A的等号做A的一个instanceof检查。B的等号做一个B的实例检查。给A a和B b:

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


如何在没有失去对称属性?使用getClass似乎并不安全,使用instanceof时我不安全?



答案永远不会将重要成员添加到子类,然后是安全使用instanceof(用于休眠)?

我读过的资料:

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

项目7和8在Josh Blochs出色的书Effective Java中, 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

解决方案

在我汇总了一些问题后,我总结了这个问题:


  • 使用instanceof,从不增加重要(
    )无法扩展可实例化的类并在保留等价合约(Bloch)的同时添加一个值组件
  • 使用getClass并且违反了Liskov替换原则



Langers表示 http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals.html



  • instanceof测试仅适用于最终类,或者至少方法equals()在超类中是final。后者基本上是
    ,意味着没有子类必须扩展超类的状态,但
    只能添加与对象的
    状态和行为无关的功能或字段,例如瞬态或静态字段。 / li>


另一方面,使用getClass()测试的实现总是
符合equals()合约;他们是正确和强大的。然而,

使用instanceof测试的实现在语义上非常不同。使用getClass()的实现不允许子类与超类对象进行
比较,即使子类
没有添加任何字段,甚至不希望覆盖equals(),也不行。
这样一个平凡的类扩展例如是在为这个微不足道的
目的定义的子类中添加
调试打印方法。如果超类禁止通过
getClass()检查进行混合类型比较,那么平凡的扩展将不会与其超类相比
。这个问题是否完全取决于
类的语义和扩展的目的。


总结 - 使用instanceof和final for equals可以避免破坏对称性,并避免hibernate的代理问题。

链接


After reading up on (again, should have done this a long time ago) implementing equals and hashcode correctly i came to these conclusions,that works for me:

If pre JDK 7: Prefer using Apache commons equalsbuilder and hashcodebuilder. (or Guava). Their javadocs contain examples of how to use them in good way.

If JDK 7++: Use the new Objects utility class

But, If writing for hibernate some special requistes appear (see sources farther down) Amongst them are the recommended usage of instanceof instead of getClass, due to hibernate creating proxys of subclasses that are lazy-loaded.

But as i understand, if doing this another potential problem occurs: The reason to use getClass is to ensure the symmetric property of the equals contract. 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.*

And by using instanceof, it's possible to not be symmetric. Example: B extends A. A's equals does an instanceof check of A. B's equals does an instanceof check of B. Give A a and B b:

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

How to implement equals with hibernate without risking losing the symmetric property? It seems i'm not safe when using getClass, and i'm not safe when using instanceof?

Is the answer to never add significant members to subclasses, and then be safe in using instanceof (for hibernate that is)?

Sources i read:

What issues should be considered when overriding equals and hashCode in Java?

Items 7 and 8 in Josh Blochs excellent book "Effective Java", http://web.archive.org/web/20110622072109/http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf

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

解决方案

After rading up some more i summarize this question with:

  • Use instanceof and you can never add significant members to subclasses.( There is no way to extend an instantiable class and add a value component while preserving the equals contract (Bloch)
  • Use getClass and you violate the Liskov substitution principle

Langers says http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals.html

  • The instanceof test is correct only for final classes or if at least method equals() is final in a superclass. The latter essentially implies that no subclass must extend the superclass's state, but can only add functionality or fields that are irrelevant for the object's state and behavior, such as transient or static fields.

Implementations using the getClass() test on the other hand always comply to the equals() contract; they are correct and robust. They are, however, semantically very different from implementations that use the instanceof test. Implementations using getClass() do not allow comparison of sub- with superclass objects, not even when the subclass does not add any fields and would not even want to override equals() . Such a "trivial" class extension would for instance be the addition of a debug-print method in a subclass defined for exactly this "trivial" purpose. If the superclass prohibits mixed-type comparison via the getClass() check, then the trivial extension would not be comparable to its superclass. Whether or not this is a problem fully depends on the semantics of the class and the purpose of the extension.

Summary - use instanceof with final for equals avoids breaking symmetry, and avoids the hibernate "proxy" problem.

Links

这篇关于如何实现等于休眠而不会冒失去对称性的风险?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆