Как реализовать на равных с Hibernate, не рискуя потерять симметричное свойство?
После прочтения (опять же, следовало бы сделать это давным-давно) правильной реализации equals и hashcode я пришел к следующим выводам, которые работают для меня:
Если до JDK 7: Предпочитаю использовать Apache Commons EqualsBbuilder и HashCodelder. (или гуава). Их 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. equals делает экземпляр проверки A. B. Equals выполняет проверку B. Приведите A a и B b:
a.equals (b) -> верно b.equals(a) -> ложно
Как реализовать на равных с Hibernate, не рискуя потерять симметричное свойство? Кажется, я не безопасен при использовании getClass, и я не безопасен при использовании instanceof?
Является ли ответом никогда не добавлять значимые элементы в подклассы, а затем безопасно использовать instanceof (для hibernate, то есть)?
Источники, которые я прочитал:
Какие проблемы следует учитывать при переопределении equals и hashCode в Java?
Пункты 7 и 8 в превосходной книге Джоша Блоха "Эффективная 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
3 ответа
После более подробного изучения я суммирую этот вопрос:
- Используйте instanceof, и вы никогда не сможете добавить значимые члены к подклассам.(Нет способа расширить экземплярный класс и добавить компонент значения при сохранении контракта equals (Bloch)
- Используйте getClass и вы нарушаете принцип подстановки Лискова
Лангерс говорит, что http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals.html
- Тест instanceof корректен только для конечных классов или если хотя бы метод equals() является окончательным в суперклассе. Последнее по существу подразумевает, что ни один подкласс не должен расширять состояние суперкласса, но может добавлять только функциональные возможности или поля, которые не имеют отношения к состоянию и поведению объекта, такие как переходные или статические поля.
Реализации, использующие тест getClass(), с другой стороны, всегда соответствуют контракту equals(); они правильные и крепкие. Однако они семантически сильно отличаются от реализаций, в которых используется экземпляр теста. Реализации, использующие getClass(), не позволяют сравнивать подкласс с объектами суперкласса, даже когда подкласс не добавляет никаких полей и даже не хочет переопределять equals() . Такое "тривиальное" расширение класса могло бы быть, например, добавлением метода debug-print в подкласс, определенный именно для этой "тривиальной" цели. Если суперкласс запрещает сравнение смешанного типа с помощью проверки getClass(), то тривиальное расширение не будет сопоставимо с его суперклассом. Является ли это проблемой или нет, полностью зависит от семантики класса и цели расширения.
Резюме - использование instanceof с final для equals позволяет избежать нарушения симметрии и избежать проблемы гибернации "прокси".
связи
Если вы хотите сравнить классы обоих объектов в методе equals, вы можете использовать Hibernate.getClass для обоих объектов перед их сравнением. Тогда вы не столкнетесь с проблемами, например, при сравнении объекта и спящего режима для объекта.
Это интересный вопрос - реализация equals
как отношение эквивалентности не тривиально, когда наследование вовлечено. Посмотрите этот подробный пост Martin Odersky et al. о реализации равенства объектов.