web-dev-qa-db-ja.com

Java equals()メソッドをオーバーライドします-動作しませんか?

今日、equals()メソッドに関する興味深い(そして非常にイライラする)問題に遭遇しました。

完全を期すために、私はIDEやデバッガーを使用していませんでした-古き良き時代のテキストエディターとSystem.outだけです。時間は非常に限られており、学校のプロジェクトでした。

とにかく-

ArrayList of Bookオブジェクトを含むことができる基本的なショッピングカートを開発していました。 CartのaddBook()removeBook()hasBook()メソッドを実装するために、BookCartに既に存在するかどうかを確認したいと思いました。だから私は行く-

public boolean equals(Book b) {
    ... // More code here - null checks
    if (b.getID() == this.getID()) return true;
    else return false;
}

テストではすべて正常に動作します。 6つのオブジェクトを作成し、それらにデータを入力します。 Cartに対して多くのadd、remove、has()操作を実行すると、すべて正常に動作します。 equals(TYPE var)またはequals(Object o) { (CAST) var }のいずれかができることを読みましたが、動作していたので、それほど重要ではないと思いました。

その後、問題に遭遇しました-Bookクラス内からonlyBookを含むIDオブジェクトを作成する必要がありました。他のデータは入力されません。基本的には次のとおりです。

public boolean hasBook(int i) {
    Book b = new Book(i);
    return hasBook(b);
}

public boolean hasBook(Book b) {
    // .. more code here
    return this.books.contains(b);
}

突然、equals(Book b)メソッドは機能しなくなりました。これは、優れたデバッガーなしで、Cartクラスが適切にテストされ、正しいと仮定して追跡するのに非常に長い時間がかかりました。 equals()メソッドを次のように交換した後:

public boolean equals(Object o) {
    Book b = (Book) o;
    ... // The rest goes here   
}

すべてが再び機能し始めました。メソッドが明確であってもBookパラメーターを使用しないことを決定した理由はありますか だった Bookオブジェクト?唯一の違いは、同じクラス内からインスタンス化され、1つのデータメンバーのみで満たされているように思われます。私はとても混乱しています。光を当ててください。

148
Josh Smeaton

Javaでは、Objectから継承されるequals()メソッドは次のとおりです。

public boolean equals(Object other);

つまり、パラメーターはObject型である必要があります。

ArrayListは正しいequalsメソッドを使用します。このメソッドでは、常にObjectのequalsを適切にオーバーライドしなかったメソッドを呼び出していました。

メソッドを正しくオーバーライドしないと、問題が発生する可能性があります。

次の値を毎回オーバーライドします:

@Override
public boolean equals(Object other){
    if (other == null) return false;
    if (other == this) return true;
    if (!(other instanceof MyClass))return false;
    MyClass otherMyClass = (MyClass)other;
    ...test other properties here...
}

@Overrideアノテーションを使用すると、とんでもない間違いをするのに役立ちます。

スーパークラスまたはインターフェイスのメソッドをオーバーライドしていると思うときはいつでも使用してください。そうすれば、間違えた場合、コンパイルエラーが発生します。

323
jjnguy

Eclipseを使用している場合は、トップメニューに移動します

ソース-> equals()およびhashCode()を生成

108
Fred

あなたの質問には少し話題から外れていますが、とにかく言及する価値があるでしょう:

Commons Lang には、equalsとhashcodeのオーバーライドに使用できるいくつかの優れたメソッドがあります。 EqualsBuilder.reflectionEquals(...) および HashCodeBuilder.reflectionHashCode(...) を確認してください。過去にたくさんの頭痛の種を救いました-もちろん、単にIDで「等しい」ことをしたいだけなら、あなたの状況に合わないかもしれません。

また、等しい(または他のメソッド)をオーバーライドするときはいつでも@Overrideアノテーションを使用する必要があることに同意します。

11
user7094

定型コードを節約する別の高速ソリューションは、 Lombok EqualsAndHashCodeアノテーション です。簡単でエレガントでカスタマイズ可能です。そしてはIDEに依存しません。例えば;

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(of={"errorNumber","messageCode"}) // Will only use this fields to generate equals.
public class ErrorMessage{

    private long        errorNumber;
    private int         numberOfParameters;
    private Level       loggingLevel;
    private String      messageCode;

イコールで使用するフィールドをカスタマイズするには、 options を参照してください。 Lombokは maven で利用可能です。 providedスコープで追加するだけです:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.14.8</version>
    <scope>provided</scope>
</dependency>
4
borjab

考慮してください:

Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...
1
bcsb1001

Android St​​udioはalt + insert ---> equalsおよびhashCodeです

例:

    @Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Proveedor proveedor = (Proveedor) o;

    return getId() == proveedor.getId();

}

@Override
public int hashCode() {
    return getId();
}
1
David Hackro

instanceOfステートメントは、equalsの実装でよく使用されます。

これは人気の落とし穴です!

問題は、instanceOfを使用すると対称性の規則に違反することです。

(object1.equals(object2) == true)if if only(object2.equals(object1))

最初のequalsがtrueであり、object2がobj1が属するクラスのサブクラスのインスタンスである場合、2番目のequalsはfalseを返します!

ob1が属するとみなされるクラスがfinalとして宣言されている場合、この問題は発生しませんが、一般的には次のようにテストする必要があります。

this.getClass() != otherObject.getClass();でない場合はfalseを返し、そうでない場合はフィールドをテストして同等かどうかを比較します!

0
Nikel8000