3

タイトルを書き留めた後、このSOの投稿を読みましたが、Javaでのequalsのバグプルーフ実装に関する質問に答えることにしました。これは私の通常の実装です

@Override
        public boolean equals(Object o){
            if(o == null) return false;
            if(o instanceof CompositePk == false) return false;
            if(this == o) return true;
            CompositePk that = (CompositePk)o;
            return new EqualsBuilder().append(this.id, that.id)
                                      .append(this.bucketId, that.bucketId)
                                      .isEquals();
        }

ApacheのEqualsBuilderを使用してありふれたことを行います。これよりもさらに簡単なのは、Netbeanの自動生成さequals(o)れた実装です

 @Override
        public boolean equals(Object obj){
        if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final TemplatesWrapper other = (TemplatesWrapper) obj;
            if (this.timeAdded != other.timeAdded && (this.timeAdded == null || !this.timeAdded.equals(other.timeAdded))) {
                return false;
            }
            return true;
    }

私はこれらを2つのdiffプロジェクトから取得しますが、どちらも同じことを達成しようとしますが、diffアプローチを使用します。どちらのスタイルを選びますか、それとも欠陥を見つけますか?

4

5 に答える 5

9

まず、がであると評価されるためnull、をテストしてから、instanceofをテストする必要はありません。foo instanceof Barfalsefoonull

ブール演算であるため、instanceof演算子の結果をと比較するのは奇妙です。falseinstanceof

クラスとの比較getClass()は、せいぜい物議を醸しています。Javaコレクションフレームワークの多くと他の多くの重要なものを書いたJoshuaBlochは、次のように述べています。

この手法(「getClassベースのequalsメソッド」)はequalsコントラクトを満たしますが、コストがかかります。getClassアプローチの欠点は、「Liskov Substitution Principle」に違反していることです。この原則では、スーパークラスインスタンスを期待するメソッドは、サブクラスインスタンスが提示されたときに適切に動作する必要があると述べています。サブクラスがいくつかの新しいメソッドを追加したり、動作を簡単に変更したりする場合(たとえば、メソッドの呼び出しごとにトレースを発行するなど)、サブクラスとスーパークラスのインスタンスが適切に相互作用しないと、プログラマーは驚かれることでしょう。「等しくなければならない」オブジェクトはそうではなく、プログラムが失敗したり、不規則に動作したりします。この問題は、Javaのコレクションがequalsメソッドに基づいているという事実によって悪化します。

特別な技術的理由がない限りinstanceof、経由で比較する代わりに使用する必要があります。getClass()

他のオブジェクトがに匹敵することを確認したthis後、プリミティブを==と、オブジェクトをと比較しますequals。メンバーオブジェクトのいずれかがnullになる可能性がある場合は、さらに複雑になります。次に、冗長な句を記述して、nullの可能性があるものを相互に比較する(またはbothNullOrEqual(Object a, Object b)メソッドを記述する)必要があります。

このEqualsBuilderアプローチは私には偽物に見えますが、それは単なる「匂い」であり、技術的には異議を唱えません。一般的に、頻繁に呼び出される可能性のあるメソッドでの余分なメソッド呼び出しは好きではありません。

Apacheは、比較をテストしnullて使用するため、偽物です。getClass()

これが私のものです:

@Override
public boolean equals(final Object o) {
    if (!(o instanceof MyClass))
        return false;
    final MyClass om = (MyClass)o;
    // compare om's fields to mine
}
于 2009-10-15T00:45:44.117 に答える
5

私はそれをこのようにします:

public boolean equals(Object ob) {
  if (ob == null) return false;
  if (ob == this) return true;

  if (!(ob instanceof MyClass)) return false; // OR
  if (ob.getClass() != getClass()) return false;

  // check relevant members
}

真ん中の2本の線が違います。1つはサブクラスが等しくなることを可能にし(最初のもの)、もう1つはそうではありません。適切な方を使用してください。

例を挙げると、AbstractListの正確な実装は関係ないため、Javaのクラスはおそらく2番目の形式を使用しListます。重要なのは、メンバーが平等で同じ立場にあるかどうかです。

逆に、Personクラスは最初の形式(instanceof)を使用する必要があります。これは、Studentサブクラスがあり、それを呼び出すPerson.equals(Student)と、Studentの追加フィールドをチェックせずにtrueが返される可能性があるのに対し、Student.equals(Person)はおそらくを返すためfalseです。可換でない場合equals()は、問題を抱えています。

equals()私は、Apacheライブラリへの不要な依存関係を作成するのではなく、IDE(IntelliJ IDEA)によって生成されたメソッドを使用する傾向があります。

于 2009-10-15T00:28:39.790 に答える
0

Apacheはあなたやcletusよりも優れています。

私の漠然とした記憶が示唆する限りinstanceof、equalsでの使用には問題があります。なぜまだなのか、はっきりとは言えません。おそらく誰かが詳しく説明するでしょう。私は間違っている可能性があります。

- 編集:

クリススティーブが以下で役立つように説明しているように、私はequals実装の「対称性」について考えていました。これに基づいて、Apacheの実装を好むという私の主張を裏付けることができます:)

于 2009-10-15T00:32:21.390 に答える
0

正直なところ、作成する必要のあるコードが少なければ少ないほど、(ほとんどの場合)より良い結果が得られます。

生成されたコードはデバッグされ、多くの人々によって使用されています。生成されたものを使用することもできます(パフォーマンスを向上させる必要がある場合は、そうしてください)。

生成されたコードを使用する利点:インスタンスフィールドが変更されたとき(およびこの生成されたコードが変更されていないとき)はいつでも、コードを簡単に再生成できます。

場合によっては、保守性について考える方が簡単です。経験則:自分で作成するコードが少なければ少ないほど、デバッグする必要も少なくなります。生成されたコードがパフォーマンスに大きな影響を与えない場合は、生成してください。

于 2009-10-15T16:31:14.440 に答える
0

説明:equalsメソッドをオーバーライドする場合は、hashCode()メソッドもオーバーライドする必要があります。したがって、以下に示すように3つのプロパティを持つクラスを検討し、すべてのプロパティが等式にとって重要であることを考慮すると、equals()実装はこれらすべてのフィールドをテストする必要があります。条件の順序は重要ではありませんが、オブジェクト間の同等性を考慮するには、すべてのフィールドが同等であるかどうかをテストする必要があります。

public class SampleClass {

  private Long id;
  private String description;
  private Date creation;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((creation == null) ? 0 : creation.hashCode());
        result = prime * result + ((description == null) ? 0 : description.hashCode());
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        boolean isEquals = true;
        if (this == obj) { isEquals = true; }
        else if (obj == null) { isEquals = false; } 
        else if (getClass() != obj.getClass()) { isEquals = false;  }
        else { 
            SampleClass other = (SampleClass) obj;
            if (creation == null) {
                if (other.creation != null) isEquals = false;
            } else if (!creation.equals(other.creation)) {
                isEquals = false;
            } else if (description == null) {
                if (other.description != null) isEquals = false;
            } else if (!description.equals(other.description)) {
                isEquals = false;
            } else  if (id == null) {
                if (other.id != null) isEquals = false;
            } else if (!id.equals(other.id)) {
                isEquals = false;
            }
        }
        return isEquals;
    }
于 2014-09-25T11:40:31.517 に答える