阅读完(再次,应该很久以前就应该这样做)正确地实现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
在提出更多建议后,我总结了以下问题:
朗格说http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals.html
* test的instanceof测试仅对最终类是正确的,或者至少在父类中equals()方法是最终的。后者实质上意味着没有子类必须扩展超类的状态,而只能添加与对象的状态和行为无关的功能或字段,例如瞬态或静态字段。 另一方面,使用getClass()测试的实现始终符合equals()合同;他们是正确和强大的。但是,它们在语义上与使用instanceof test的实现有很大不同。使用getClass()的实现不允许将子类与超类对象进行比较,即使子类未添加任何字段并且甚至不希望覆盖equals()也不行。这种“琐碎”的类扩展例如是在为该“琐碎”目的而定义的子类中添加了调试打印方法。如果超类禁止通过getClass()检查进行混合类型比较,那么普通扩展将无法与其超类进行比较。
* test的instanceof测试仅对最终类是正确的,或者至少在父类中equals()方法是最终的。后者实质上意味着没有子类必须扩展超类的状态,而只能添加与对象的状态和行为无关的功能或字段,例如瞬态或静态字段。
另一方面,使用getClass()测试的实现始终符合equals()合同;他们是正确和强大的。但是,它们在语义上与使用instanceof test的实现有很大不同。使用getClass()的实现不允许将子类与超类对象进行比较,即使子类未添加任何字段并且甚至不希望覆盖equals()也不行。这种“琐碎”的类扩展例如是在为该“琐碎”目的而定义的子类中添加了调试打印方法。如果超类禁止通过getClass()检查进行混合类型比较,那么普通扩展将无法与其超类进行比较。
总结-将instanceof与final for equals一起使用可避免破坏对称性,并避免hibernate的“代理”问题。