2013-02-10 7 views
11

Dopo aver letto su (di nuovo, avrebbe dovuto fare questo molto tempo fa) pari e hashcode attuare correttamente sono venuto a queste conclusioni, che funziona per me:Come implementare equals con hibernate senza rischiare di perdere la proprietà simmetrica?

Se pre JDK 7: Preferisco usando Apache Commons equalsbuilder e hashcodebuilder. (o Guava). Le loro javadoc contengono esempi di come usarle nel modo giusto.

Se JDK 7 ++: Utilizzare la nuova classe di utilità oggetti

Ma, se la scrittura per ibernazione appaiono alcuni requistes speciali (vedi fonti più in basso) Tra loro sono l'utilizzo raccomandata di instanceof anziché getClass, a causa dell'ibernazione della creazione di proxy di sottoclassi caricate in modalità lazy.

Ma come ho capito, se si verifica un altro potenziale problema: Il motivo per utilizzare getClass è garantire la proprietà simmetrica del contratto di uguale. 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.* 

E utilizzando instanceof, è possibile non essere simmetrici. Esempio: B estende eguali A. A fa un controllo instanceof di uguali A. B non un controllo instanceof di B. Give A ae B B:

a.equals (B) -> vere b.equals (a) -> false

Come implementare equamente con l'ibernazione senza rischiare di perdere la proprietà simmetrica? Sembra che non sono sicuro quando uso getClass e non sono sicuro quando utilizzo instanceof?

È la risposta per non aggiungere mai membri significativi a sottoclassi e quindi essere sicuri nell'uso di instanceof (per l'ibernazione)?

Fonti leggo:

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

Articoli da 7 e 8 in Josh Blochs eccellente libro "Effective Java", http://web.archive.org/web/20110622072109/http://java.sun.com/developer/Books/effectivejava/Chapter3.pdf

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

risposta

2

Dopo rading un po 'più riassumo a questa domanda con:

  • Usa instanceof e non si può mai aggiungere membri significativi alle sottoclassi.( Non v'è alcun modo per estendere una classe creare istanze e aggiungere un componente di valore, preservando il contratto equals (Bloch)
  • Usa getClass e si viola il principio di sostituzione Liskov

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

  • L'istanza di prova è corretta solo per le classi finali o se almeno il metodo equals() è finale in una superclasse.Questo essenzialmente implica che nessuna sottoclasse deve estendere lo stato della superclasse, ma può aggiunge funzionalità o campi non pertinenti allo stato dell'oggetto e al comportamento, come i campi transitori o statici.

Le implementazioni che utilizzano il test getClass() d'altra parte sempre sono conformi al contratto equals(); sono corretti e robusti. Sono , tuttavia, semanticamente molto diversi dalle implementazioni che utilizzano l'instanceof test. Le implementazioni che utilizzano getClass() non consentono il confronto tra di oggetti secondari con superclasse, nemmeno quando la sottoclasse non aggiunge campi e non vorrebbe nemmeno sovrascrivere equals(). Un'estensione di classe così "banale" sarebbe ad esempio l'aggiunta di a un metodo di debug-print in una sottoclasse definita esattamente per questo scopo "banale" . Se la superclasse proibisce il confronto di tipo misto tramite il controllo getClass(), l'estensione banale non sarebbe paragonabile allo alla sua superclasse. Se questo è un problema dipende completamente da la semantica della classe e lo scopo dell'estensione.

Sommario - utilizzare instanceof con finale per eguali evita la rottura di simmetria, ed evita il problema di ibernazione "proxy".

Link

2

Questa è una domanda interessante - l'implementazione di equals come relazione di equivalenza non è banale quando è coinvolta l'ereditarietà. Vedi this in-depth post di Martin Odersky et al. sull'implementazione dell'uguaglianza degli oggetti.

+0

Grazie per i collegamenti. – Beamie

4

Se si desidera confrontare le classi di entrambi gli oggetti nel metodo equals è possibile utilizzare Hibernate.getClass su entrambi gli oggetti prima di confrontarli. Quindi non ti imbatti in problemi, ad es. quando si confronta un oggetto e un proxy di ibernazione per un oggetto.

Problemi correlati