2012-10-31 15 views
12

私は単純な基本クラスを持っていますが、これは後で多くの個別のクラスによって拡張され、新しいフィールドを導入する可能性があります。私は基底クラスでequalsメソッドを定義しましたが、いくつかのサブクラスではそれをオーバーライドしました。定義をベース/サブクラスに混在させても問題ありませんか?私の場合は、同じフィールドをチェックするコードの重複を避けることでした。基本クラスとサブクラスのJava等価メソッド

+6

ミキシング定義の意味を説明できますか?ありがとう。 – tjg184

+0

基本クラスに1つの定義があります。これはオーバーライドされる場合とされない場合があります。私は "基本クラスの混合アプローチは、スーパークラスを定義するためのアドバイスのためにサブクラス対" – Bober02

答えて

22

Angelika Langerの"Implementing equals() To Allow Mixed-Type Comparison"をご覧ください。ここ

はいくつかの問題と可能な解決策の簡単な説明である:

それが対称である:null以外の参照値xとyについて

ザ契約は(とりわけ)と言うに等しいですy.equals(x)がtrueを返す場合に限り、x.equals(y)はtrueを返す必要があります。あなたのサブクラスは、新しいフィールドを導入されていて、このサブクラスのオブジェクトへの基底クラス(または等号をオーバーライドしていない別のサブクラス)のオブジェクトを比較している場合は、問題を得るかもしれない意味

は、クラスの比較でinstanceof -checkを交換してください:あなたは

BaseClass baseClass = new BaseClass(); 
BadSubClass subClass = new BadSubClass(); 

System.out.println(baseClass.equals(subClass)); // prints 'true' 
System.out.println(subClass.equals(baseClass)); // prints 'false' 

が可能な解決策を得るため

class BaseClass { 
    private int field1 = 0; 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof BaseClass) { 
      return field1 == ((BaseClass) obj).field1; 
     } 
     return false; 
    } 
} 

class BadSubClass extends BaseClass { 
    private int field2 = 0; 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof BadSubClass) { 
      return super.equals(obj) 
        && field2 == ((BadSubClass) obj).field2; 
     } 
     return false; 
    } 
} 

は、次の手順を実行しないでください

obj != null && obj.getClass() == getClass() 

BaseClassのオブジェクトは、どのサブクラスのオブジェクトとも決して等しくありません。あなたがequals方法の@Overrideせずに別の​​を作成した場合

は、2​​-objectsは(BaseClass.equalsチェックが決定した場合そう)箱から出して、しかし​​に等しくなることはありません-object互いに等しくすることができますBaseClass-オブジェクト。

class BaseClass { 
    private int field1 = 0; 

    @Override 
    public boolean equals(Object obj) { 
     if (obj != null && obj.getClass() == getClass()) { 
      return field1 == ((BaseClass) obj).field1; 
     } 
     return false; 
    } 
} 

class GoodSubClass extends BaseClass { 
    private int field2 = 0; 

    @Override 
    public boolean equals(Object obj) { 
     if (obj instanceof GoodSubClass) { 
      return super.equals(obj) && field2 == ((GoodSubClass) obj).field2; 
     } 
     return false; 
    } 
} 

より高度な問題とその解決策のために、上記の記事を参照してください:次のように

良い実装がある可能性があります。

+0

Angelika Langerの記事リンクありがとう。これはLiskov置換原則に違反しますが、AFAIK。 Joshua Blockの "Effective Java"をもう一度見てください。 (私はまだ完全な記事を読んでいない。) – Puce

+1

o.getClass()の何が問題なの?= this.getClass()? – Mukul

+0

@Mukul実際には、追加のチェックをしなくても、すべてを壊すことなく 'super.equals()'を呼び出すことができれば、equalsメソッドをオーバーライドする必要がなくなるので、もっと良いと思います。私はちょうど編集に従ってそれを提出した – Qw3ry

0

は、あなたがコードの重複

public class BaseClass { 
    public boolean equals(BaseClass other) { 
    return (other.getBlahblah() == this.Blahblah && .....); 
    } 
} 

public class DerivedClass extends BaseClass { 
    public boolean equals(DerivedClass other) { 
    return (super(other) && other.getNewAttribute() == this.NewAttribute.....); 
    } 
} 
+1

+1を定義すると言っていた。 1つのノート - それは有効なJavaコードではない、それを修正するためにクールだろう(私はそれが例として擬似コードかもしれないことを理解する)。 –

+0

ありがとうございます。私はちょうどほとんどのものをチェックすることなくそれをマッシュアウトした。私はJavaをやっていて、内部で他の構文や呼び出しをしていたにちがいありません。 – Grambot

+0

オブジェクトの等価をオーバーライドするのではなく、ブロッキへの逆参照のために –

0

かなり有効なアプローチの必要性を防ぐために拡張しているクラスのメソッドを呼び出すためにsuper()メソッドを使用することができます。問題はサブクラスの1つにありますは、その親によってバインドされているequalsの定義を保持する必要があります。そうでなければ、実行時にいくつかの非常にユニークなシナリオが発生する可能性のある関数equalsが壊れています。

2

いいえ、equalsメソッドに関連する新しいフィールドを導入するときは、equals規約に準拠することはできません。詳細はJoshua Blochの "Effective Java"を参照してください。

編集:

私は今手元に本を持っていないが、私はインスタンス化できない/ベースクラスが抽象的であるならば、それはOKだと思います。私は推測

+0

+1をオーバーロードします。それは本当だから – Jerome

+0

それは抽象的な:) – Bober02

0

は、それはJavaがしたsuperclassようにequals(Object obj)hashCode()メソッドの実装を提供するために最適です。我々はJavaが基本クラスjava.lang.ObjecthashCode() and equals(Object obj)メソッドの実装を提供していることを知っており、必要なときはoverrideclassに入れています。

0

以下はすべてのケースを処理するわけではありませんが、かなり実用的であることがわかりました。私はSuperClassとSubClassの両方を使っているときにこれを何度も使ってきました。私はそれらを相互比較したくないですが、SubClassのためにすべてのSuperClass equals()を再実装したくありません。これは、ハンドル:

  • a.equals(b)は== b.equals(a)の
  • は、フィールド比較コードを簡単に任意のサブクラスの深さ
  • Subclass.equals(スーパークラス)のために一般
  • と重複しない
      ==偽
    • Superclass.equals(サブクラス)==偽

    コード例

    // implement both strict and asymmetric equality 
    class SuperClass { 
        public int f1; 
        public boolean looseEquals(Object o) { 
         if (!(o instanceof SuperClass)) return false; 
         SuperClass other = (SuperClass)o; 
         return f1 == other.f1; 
        } 
        @Override public boolean equals(Object o) { 
         return looseEquals(o) && this.getClass() == o.getClass(); 
        } 
    } 
    class SubClass extends SuperClass { 
        public int f2; 
        @Override public boolean looseEquals(Object o) { 
         if (!super.looseEquals(o)) return false; 
         if (!(o instanceof SubClass)) return false; 
         SubClass other = (SubClass)o; 
         return f2 == other.f2; 
        } 
        // no need to override equals() 
    } 
    
  • 関連する問題