質問

この質問は、特に、多数のフィールドを持つオブジェクトの equals() メソッドのオーバーライドに関連しています。まず最初に言っておきますが、この大きなオブジェクトはオブジェクト指向の原則に違反せずに複数のコンポーネントに分割することはできないため、「どのクラスも x 個を超えるフィールドを持つべきではない」と言っても役に立ちません。

次に、フィールドの 1 つが等しいかどうかをチェックするのを忘れたときに問題が発生しました。したがって、私のequalsメソッドは間違っていました。次に、リフレクションを使用することを考えました。

--code removed because it was too distracting--

この投稿の目的は必ずしもコードをリファクタリングすることではなく (これは私が使用しているコードでもありません)、代わりにこれが良いアイデアかどうかについて意見を得ることが目的です。

長所:

  • 新しいフィールドが追加されると、自動的に追加されます
  • このメソッドは 30 個の if ステートメントよりもはるかに簡潔です

短所:

  • 新しいフィールドが追加されると、自動的に組み込まれますが、これが望ましくない場合があります。
  • パフォーマンス:これはもっと遅くなるはずですが、プロファイラーを起動する必要性を感じません
  • 比較時に無視する特定のフィールドをホワイトリストに登録するのは少し見苦しいです

何かご意見は?

役に立ちましたか?

解決

パフォーマンス上の理由からホワイトリストに登録したい場合は、比較するフィールドを示すアノテーションの使用を検討してください。また、フィールドに適切な実装がない場合、この実装は機能しません。 equals().

追伸この道を行くなら equals(), 、同様のことを行うことを忘れないでください。 hashCode().

追伸すでに検討済みだと信じています ハッシュコードビルダー そして イコールビルダー.

他のヒント

Eclipse、FFSを使用してください!

所有している hashCode メソッドと等しいメソッドを削除します。

ファイルを右クリックします。

「ソース」->「ハッシュコードと等しいものを生成...」を選択します。

終わり!もう反射の心配はありません。

追加されたフィールドごとにこの手順を繰り返します。アウトライン ビューを使用して 2 つのメソッドを削除し、Eclipse にメソッドを自動生成させるだけです。

リフレクション アプローチを採用する場合でも、EqualsBuilder は依然としてあなたの友人です。

 public boolean equals(Object obj) {
    return EqualsBuilder.reflectionEquals(this, obj);
 }

心配な場合は次のことを考えてください。

1/ フィールドを追加または削除するときに、等価性をチェックするための一連の if ステートメントを更新するのを忘れます。

2/ これをequals()メソッドで実行した場合のパフォーマンス。

次のことを試してください。

a/equals() メソッドでの長い if ステートメントのシーケンスの使用に戻ります。

b/ フィールドのリスト (文字列配列内) を含み、そのリストを現実 (つまり、反映されたフィールド) と照合してチェックする関数を 1 つ用意します。一致しない場合は例外がスローされます。

c/ このオブジェクトのコンストラクターで、この関数への同期された 1 回だけ実行される呼び出しを行います (シングルトン パターンと同様)。つまり、これがこのクラスによって構築された最初のオブジェクトである場合は、上記の (b) で説明したチェック関数を呼び出します。

この例外により、反映されたフィールドと一致するように if ステートメントを更新していない場合は、プログラムを実行するとすぐにわかります。次に、if ステートメントを修正し、上記 (b) のフィールド リストを更新します。

後続のオブジェクトの構築ではこのチェックは行われず、equals() メソッドは可能な最大速度で実行されます。

試してみましたが、このアプローチでは本当の問題を見つけることができませんでした (StackOverflow には優れた頭脳が存在する可能性があります) - 1 回実行の動作については、各オブジェクト構造に追加の条件チェックがありますが、それはかなり些細なことのようです。

十分に努力すれば、if ステートメントがフィールド リストおよび反映されたフィールドと一致しない可能性はありますが、例外により、フィールド リストが反映されたフィールドと一致することが保証され、if ステートメントとフィールドを確実に更新するだけで済みます。同時にリストアップします。

いつでも、equals メソッド内で必要なフィールド、または必要としないフィールドに注釈を付けることができます。これは、単純で単純な変更です。

パフォーマンスは明らかにオブジェクトが実際に比較される頻度に関係しますが、多くのフレームワークはハッシュ マップを使用するため、思ったよりも等号が使用されている可能性があります。

また、ハッシュ マップに関して言えば、hashCode メソッドにも同じ問題があります。

最後に、すべてのフィールドが等しいかどうかを比較する必要は本当にあるのでしょうか?

コードにいくつかのバグがあります。

  1. と仮定することはできません this そして obj 同じクラスです。実際、それは明示的に許可されています obj 他のクラスになります。から始めることができます if ( ! obj instanceof myClass ) return false; しかしこれは まだ正しくありません なぜなら obj のサブクラスになる可能性があります this 重要なフィールドが追加されています。
  2. サポートしなければなりません null の値 obj シンプルな if ( obj == null ) return false;
  3. 治療はできません null と空の文字列は等しいものとします。代わりに治療してください null 特に。ここでの最も簡単な方法は、比較することから始めることです Field.get(obj) == Field.get(this). 。両方が等しい場合、または両方がたまたま同じオブジェクトを指している場合、これは高速です。(注記:これも最適化であり、これは遅いルーチンであるため必要です。)これが失敗した場合は、高速なルーチンを使用できます。 if ( Field.get(obj) == null || Field.get(this) == null ) return false; 正確に 1 つであるケースを処理する null. 。ようやくいつも通り使えるようになります equals().
  4. あなたは使っていない foundMismatch

私もハンクさんの意見に同意します [HashCodeBuilder][1] そして [EqualsBuilder][2] の方が良い方法です。保守が簡単で、定型的なコードが少なく、これらの問題をすべて回避できます。

注釈を使用してフィールドをチェックから除外できます

例えば

@IgnoreEquals
String fieldThatShouldNotBeCompared;

そしてもちろん、汎用のequalsメソッドにアノテーションが存在するかどうかを確認します。

フィールドの名前にアクセスできる場合は、含めたくないフィールドが常に「local」または「nochk」などで始まることを標準にしてはいかがでしょうか。

次に、これで始まるすべてのフィールドをブラックリストに登録します (コードはそれほど醜くなりません)。

もう少し遅いのは間違いありません。更新のしやすさと実行速度を入れ替えるかどうかを決定する必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top