14

非常に多くの場合hashcode()equals()単に機能しない OO コードベースがあります。主な理由は次のとおりです。

オブジェクト指向の抽象化の利点を諦めない限り、インスタンス化可能なクラスを拡張して値コンポーネントを追加する方法はありません。

これは、Joshua Bloch による「Effective Java」からの引用であり、このテーマについては、次の Artima の優れた記事で詳しく説明しています。

http://www.artima.com/lejava/articles/equality.html

これは、この質問の目的ではありません。

問題は、場合によっては契約を満たすことができないという事実があることがわかった場合、UnsupportedOperationExceptionを自動的に作成してスローequals()するクリーンな方法は何でしょうか?hashcode()equals()

注釈は機能しますか? 私は次のようなことを考えています@NotNull:すべての@NotNull契約違反は自動的に例外をスローし、パラメータ/戻り値に注釈を付ける以外に何もする必要はありません@NotNull.

同じ検証/スロー例外コードを常に繰り返すのではなく、8 文字 ("@NotNull") であるため便利です。

私が懸念しているケースでhashCode()/equals()は、意味をなさないすべての実装で、常に同じことを繰り返しています。

@Override
public int hashCode() {
    throw new UnsupportedOperationException( "contract violation: calling hashCode() on such an object makes no sense" );
}

@Override
public boolean equals( Object o ) {
    throw new UnsupportedOperationException( "contract violation: calling equals() on such an object makes no sense" );
}

ただし、これはエラーが発生しやすくなります。誤ってこれをカット/ペーストするのを忘れて、ユーザーがそのようなオブジェクトを誤用する可能性があります (たとえば、デフォルトの Java コレクションに入れようとするなど)。

または、この動作を作成するための注釈を作成できない場合、AOP は機能しますか?

興味深いことに、実際の問題は Java 階層の存在そのものでhashCode()ありequals()、Java 階層の最上位にあり、場合によっては意味がありません。では、この問題をきれいに処理するにはどうすればよいでしょうか。

4

4 に答える 4

10

そもそも、これがObjectの問題でhashCodeあり、Objectで定義されているというあなたの評価に同意します。equals私は長い間、平等は注文と同じように扱われるべきだという見解を持っていました。「Xのインスタンスと比較できる」というインターフェースと「Xの2つのインスタンスを比較できる」というインターフェースがあります。

一方、これは実際にあなたにバグを引き起こしましたか?人々は使用しようとしていてequalshashCodeどこで使用すべきではありませんか?コードベース内のすべてのクラスに例外をスローさせることができたとしても、それらのメソッドが不適切に呼び出された場合、JDKまたはサードパーティのライブラリに関係なく、使用している他のクラスには当てはまりません。

通常の注釈処理であろうと他の何かであろうと、何らかの形のAOPでこれを行うことができると確信していますが、報酬が努力する価値があるという証拠はありますか?

別の見方をすると、これは、すでにオーバーライドしている別のクラスを拡張している場合のみです。それ以外の場合は、ObjectのhashCode/equalsメソッドの「equality=identity」の性質を使用できます。これは引き続き便利です。このカテゴリに分類されるクラスは非常にたくさんありますか?リフレクションを介してそのようなすべてのタイプを見つける単体テストを作成し、/を呼び出すときにそれらのタイプが例外をスローすることを確認できませんか?(これは、パラメーターのないコンストラクターがある場合は自動化されるか、チェックされたタイプの手動リストがある場合があります。「既知の良好」リストにない新しいタイプがある場合、単体テストは失敗する可能性があります。)hashCodeequalshashCodeequals

于 2010-02-05T07:19:49.423 に答える
6

「場合によっては equals() 契約を満たすことができない」と考える理由がわかりませんか? 平等の意味はクラスによって定義されます。したがって、Object の equal を使用することは完全に有効です。equals をオーバーライドしていない場合は、各インスタンスを一意として定義しています。

equals は常にオーバーライドが必要なメソッドの 1 つであり、すべてのフィールドをチェックする必要があるという誤解があるようです。私は反対のことを主張します.equalsの定義が異なる場合を除き、equalsをオーバーライドしないでください。

また、artima の記事、特に「落とし穴 #3: ミュータブル フィールドに関して equals を定義する」にも同意しません。クラスが可変フィールドに基づいて同等性を定義することは完全に有効です。コレクションで使用する場合、これを認識するのはユーザー次第です。可変オブジェクトがその可変状態で等価性を定義する場合、1 つのインスタンスが変更された後に 2 つのインスタンスが等しいとは期待しないでください。

UnsupportedOperation をスローすることは、equals のスプリントに違反していると思います。オブジェクトの equals 状態:

クラス Object の equals メソッドは、オブジェクトに対して最も識別可能な等価関係を実装します。つまり、null 以外の参照値 x と y の場合、このメソッドは、x と y が同じオブジェクトを参照している (x == y の値が true である) 場合にのみ true を返します。

したがって、オブジェクトの equals 定義またはオーバーライドされた equals 定義に応じて、equals を呼び出して true または false の値を取得できるはずです。

于 2010-02-05T08:13:45.977 に答える
4

IDE(Eclipse / NetBeans / IntelliJ)にメソッドhashCode()equals()メソッドを生成させてみませんか。彼らはそれでかなり良い仕事をしています。

もちろん、AOPは機能しますが、かなり複雑です。そしてこれは、コレクションやユーティリティがほとんどない状態でこれらのオブジェクトを使用できないことを意味します。

もう1つの論理的な解決策は、機能しないメソッドの実装を削除することです。これにより、実装のみが効果的に残りObjectます。

于 2010-02-05T07:20:41.933 に答える
1

Java または .NET のすべてのオブジェクト間で定義できる等価関係が少なくとも 2 つあります。

  • 2 つのオブジェクト参照 X と Y は、X を Y への参照で上書きしても、X または Y のメンバーの現在または将来の動作が変わらない場合、完全に等価です。

  • 2 つのオブジェクト参照 X と Y は、同一性関連のハッシュ関数から返された値を永続化していないプログラムで、X へのすべての参照を Y へのすべての参照と交換すると、プログラムの状態が変更されないままになる場合、同等の状態になります。

XFordBlazer を指す参照 ( ) が 1 つあります。Yシャムキャットを指す別の ( ) があります。それらは同等ですか?いいえ、そうではないので、X.equals(Y)false にする必要があります。オブジェクトの型が互いに関係を持たないという事実は問題ではありません。どちらかといえば、それは物事をより簡単にします (シャム猫に相当することができる唯一のものが別のシャム猫である場合、それは別のシャム猫でYはないという事実他のものを調べる必要がないことをSiameseCat意味します。X.equals()

特定のオブジェクトが等価性の最初または 2 番目の定義を実装する必要があるかどうかについて議論があるかもしれませんがequals、状態の他の側面に関係なく、異なるオブジェクトを不等として報告するオブジェクトは、それ自体と一貫性があることに注意してください (X の場合)。 .Equals(X) は X.Equals(Y) と一致しません。つまり、Y は X と同じように動作しません)。したがって、equalsから継承されたデフォルトの定義objectは、完全に適切で意味のある定義です。

問題が発生する可能性がある唯一の状況はhashCode、HashTable に格納されているオブジェクトの一部の側面をコードが変更する可能性がある場合です (賢明ではありません)。そのための適切な救済策hashCodeは、オブジェクトの状態の変更可能な側面に依存しないことです。オブジェクトの状態に、そのクラス以外に意味のある不変の側面がない場合は、単にそのクラスの任意の数値を作成し、hashCode常にそれを返す必要があります。大きなハッシュ テーブルは、このようなオブジェクトではうまく機能しませんが、小さなハッシュ コードは問題なく機能します。型の適切なハッシュ コードを定義できないという事実は、12 個ほどの項目が含まれる HashTable でその型を使用することを妨げるべきではありません。

于 2013-08-04T17:19:15.903 に答える