12

equals と hashcode を正しく実装することを読んだ後 (これもずっと前にこれを行うべきでした)、次の結論に達しました。

JDK 7 より前の場合: Apache commons equalsbuilder および hashcodebuilder を使用することをお勧めします。(またはグアバ)。それらの javadoc には、それらを適切に使用する方法の例が含まれています。

JDK 7++ の場合: 新しい Objects ユーティリティ クラスを使用します。

ただし、hibernate 用に作成する場合、いくつかの特別な要件が表示されます (下のソースを参照)。その中には、hibernate が遅延ロードされるサブクラスのプロキシを作成するため、 getClassの代わりにinstanceofを使用することをお勧めします。

しかし、私が理解しているように、これを行うと別の潜在的な問題が発生します。getClass を使用する理由は、equals 契約の対称プロパティを確保するためです。JavaDoc:

*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 の instanceof チェックを行います。B の equals は B の instanceof チェックを行います。A a と B b を与えます。

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

対称プロパティを失う危険を冒すことなく、hibernate で equals を実装する方法は? getClass を使用するときは安全ではないようで、instanceof を使用するときは安全ではありませんか?

重要なメンバーをサブクラスに決して追加せず、instanceof を使用しても安全であるという答えはありますか (休止状態の場合)?

私が読んだソース:

Java で equals と hashCode をオーバーライドする場合、どのような問題を考慮する必要がありますか?

Josh Bloch の優れた本「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

4

3 に答える 3

4

equals メソッドで両方のオブジェクトのクラスを比較したい場合は、比較する前に両方のオブジェクトでHibernate.getClassを使用できます。そうすれば、オブジェクトとオブジェクトの休止状態プロキシを比較するときなど、問題に遭遇することはありません。

于 2013-10-23T13:12:15.610 に答える
3

もう少し詳しく調べた後、この質問を次のように要約します。

  • instanceof を使用すると、重要なメンバーをサブクラスに追加することはできません (インスタンス化可能なクラスを拡張し、等号契約を維持しながら値コンポーネントを追加する方法はありません (Bloch)
  • getClass を使用すると、Liskov 置換原則に違反します

Langers はhttp://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals.htmlを言う

  • instanceof テストは、final クラスの場合、または少なくともメソッド equals() がスーパークラスで final である場合にのみ正しいです。後者は基本的に、サブクラスがスーパークラスの状態を拡張してはならず、オブジェクトの状態や動作に関係のない機能やフィールド (一時フィールドや静的フィールドなど) のみを追加できることを意味します。

一方、getClass() テストを使用する実装は、常に equals() 契約に準拠します。それらは正確で堅牢です。ただし、これらは instanceof テストを使用する実装とは意味的に大きく異なります。getClass() を使用する実装では、サブクラスがフィールドを追加せず、 equals() をオーバーライドしたくない場合でも、サブクラス オブジェクトとスーパークラス オブジェクトを比較できません。このような「些細な」クラス拡張は、たとえば、まさにこの「些細な」目的のために定義されたサブクラスに debug-print メソッドを追加することです。スーパークラスが getClass() チェックによる混合型比較を禁止している場合、自明な拡張機能はそのスーパークラスと比較できません。

要約 - equals に対して final で instanceof を使用すると、対称性の破れが回避され、休止状態の「プロキシ」の問題が回避されます。

リンク

于 2013-05-26T15:42:28.187 に答える
2

これは興味深い質問equalsです。継承が関係している場合、等価関係として実装することは簡単ではありません。Martin Odersky らによるこの詳細な投稿を参照してください。オブジェクトの等価性の実装について。

于 2013-02-10T22:34:08.957 に答える