2

サブクラスを扱うときに equals メソッドをオーバーライドする最善の方法について読んでいますが、ここでかなりの数の投稿を見つけました。彼らは、異なるサブクラスのオブジェクトを比較するために、instanceof または getClass() を使用してソリューションを実装するさまざまな方法を推奨しています。

ただし、Effective Java に関しては、私の理解では (私はこれに慣れていないので、間違っている可能性があります!) 最終的にはどちらも問題になる可能性があると Bloch 氏は主張しています。オブジェクト指向の抽象化の利点を放棄したくない場合を除いて、等号契約を維持しながらコンポーネントを作成する必要があります。」次に、「継承よりも構成を優先する」ことをお勧めします。

したがって、AbstractClass、ConcreteClass1、および ConcreteClass2 というクラス階層を扱っています。ConcreteClass1 は AbstractClass を拡張し、ConcreteClass2 は ConcreteClass1 を拡張します。現時点では、AbstractClass のみが equals メソッドをオーバーライドします。

したがって、AbstractClass では次のようになります。

public abstract class AbstractClass {
        private String id;


        public boolean equals(Object other) {
            return other != null && other.getClass().equals(getClass())
                    && id.equals(((AbstractClass) other).id);
        }

    }

そして、ConcreteClass1 には次のものがあります。

public class ConcreteClassOne extends AbstractClass
{
  private final AbstractClass parent;

  public ConcreteClassOne( String anId, AbstractClass aParent )
  {
    super( anId );

    parent = aParent;
  }

}

最後に ConcreteClassTwo には次のものがあります。

public class ConcreteClassTwo extends ConcreteClassOne
{
  private static int nextTrackingNo = 0;

  private final int trackingNo;

  public ConcreteClassTwo ( String anId )
  {
    super( anId, null );

    trackingNo= getNextTrackingNo();
  }
}

したがって、重要なフィールドparentとtrackingNoを含めるには、ConcreteClassOneとConcreteClassTwoの両方でequalsメソッドをオーバーライドする必要があると思います。デザインを変更することは許可されていないため、構成を使用することはできません。助言がありますか?

4

3 に答える 3

2

最も簡単な方法は、具象クラスと抽象クラスの両方で equals() を拡張することです。

public class ConcreteClassTwo extends ConcreteClassOne {
    public boolean equals(Object other) {
        boolean rv = super.equals( other );
        if ( other instanceof ConcreteClassTwo ) {
           rv = rv && (this.trackingNo == ((ConcreteClassTwo) other).trackingNo);
        }
        return rv;
    }
}
于 2013-05-21T13:15:52.153 に答える
1

equalsの両方がConcreteClassOneありConcreteClassTwo、の対称性equalsが壊れている場合:

Object c1 = new ConcreteClassOne(),
       c2 = new ConcreteClassTwo();
System.out.println("c1=c2? " + c1.equals(c2)");
System.out.println("c2=c1? " + c2.equals(c1)");

さて、equals通常の方法で実装すると、これは印刷されます

true
false

c2.equalsあなたには がありinstanceof ConcreteClassTwo、これは で失敗しますがc1、反対の場合は同様のチェックに合格します。

于 2013-05-21T13:27:02.080 に答える
0

基本クラス コントラクトは、次の 2 つのアプローチのいずれかを指定する必要があります。派生クラス オブジェクトは、まったく同じ classではない他のオブジェクトに対して自分自身を考慮してはならないことを宣言するか、すべての派生クラス オブジェクトを基本クラスの契約によって定義された正規の形式に変換可能であり、正規の形式が一致する場合、2 つの不変オブジェクトは同等と見なされます。

後者の状況の例は、メソッドint GetSize()およびを持つ ImmutableSquareFloatMatrix 基本クラスfloat GetCell(int row, int column)です。一般的な実装では、(size*size) float 値の配列が含まれますが、たとえば、サイズを指定する唯一のフィールドを持つクラス、サイズを指定するフィールドと値を指定するフィールドを持つクラスを持つこともZeroMatrixできIdentityMatrixますConstantMatrix。すべてのセルに対して返されるDiagonalMatrix、対角線の項目のみを含む 1 次元配列を持つクラス (GetCellメソッドは他のすべてに対してゼロを返します) など。

から派生したクラスの 2 つのインスタンスが与えられた場合、ImmutableSquareFloatMatrixそれらのサイズを比較してから、その中のすべての値を比較することでそれらを比較できますが、多くの場合、それは非効率的です。比較対象のオブジェクトのいずれかが他方のオブジェクトのタイプを「知っている」場合、効率を大幅に改善できる可能性があります。どちらのオブジェクトも相手を認識していない場合、デフォルトの比較方法に戻すのは遅くなる可能性がありますが、いずれにしても正しい結果が得られます。

その状況を処理する実行可能なアプローチは、基本型にequals2メソッドを実装させることです。このメソッドは、他のオブジェクトの特別な知識が等しいと判断できる場合は 1 を返し、等しくないと判断できる場合は -1 を返します。または 0 を返します。それが言えなかった場合。いずれかの型のequals2メソッドがそれらが等しくないことを認識している場合、それらは等しくありません。それ以外の場合、どちらかが等しいことを知っている場合、それらは等しいです。それ以外の場合は、セルごとの比較を使用して等しいかどうかをテストします。

于 2013-05-21T18:03:58.567 に答える