153

今日、メソッドで興味深い (そして非常に苛立たしい) 問題に遭遇しましたequals()。これにより、十分にテストされたクラスと思われるものがクラッシュし、追跡に非常に長い時間がかかったバグが発生しました。

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

とにかく -

オブジェクトArrayListBook含むことができる基本的なショッピングカートを開発していました。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 つのオブジェクトを作成し、それらにデータを入力します。で多くの追加、削除、has() 操作を実行するCartと、すべて正常に動作します。私はあなたが持つことができるequals(TYPE var)equals(Object o) { (CAST) var }、それが機能していたので、あまり問題ではないと仮定したことを読みました.

その後、問題が発生しました。 Book クラス内からのみBookを含むオブジェクトを作成する必要がありました。他のデータは入力されません。基本的には次のとおりです。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 つのデータ メンバーだけで満たされているように見えました。私は非常に混乱しています。光を当ててください?

4

8 に答える 8

335

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

public boolean equals(Object other);

つまり、パラメータのタイプは である必要がありますObject。これはオーバーライドと呼ばれます。メソッドは、メソッドへのオーバーロードpublic boolean equals(Book other)と呼ばれるものを実行します。equals()

オーバーロードされたメソッドではなくArrayList、オーバーライドさequals()れたメソッドを使用して内容を比較します (例:contains()equals()メソッド) 。ほとんどのコードで、 の equals を適切にオーバーライドしなかったものを呼び出すことは問題ありませんでしたが、 とは互換性がありませんでした。ObjectArrayList

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

私は毎回次のようにオーバーライドします:

@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ばかげたミスを大幅に減らすことができます。

スーパークラスまたはインターフェースのメソッドをオーバーライドしていると思われる場合はいつでも使用してください。このように、間違った方法で実行すると、コンパイル エラーが発生します。

于 2008-10-09T04:27:54.103 に答える
111

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

ソース->equals()とhashCode()を生成します

于 2011-06-02T16:15:43.400 に答える
11

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

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

@Overrideまた、 equals (またはその他のメソッド) をオーバーライドするときはいつでも注釈を使用する必要があることに同意します。

于 2008-10-09T08:27:54.993 に答える
5

ボイラープレート コードを節約するもう 1 つの高速なソリューションは、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;

equals で使用するフィールドをカスタマイズするために使用できるオプションを参照してください。ロンボクはmavenで利用できます。提供されたスコープで追加するだけです:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.14.8</version>
    <scope>provided</scope>
</dependency>
于 2014-10-17T11:24:19.530 に答える
1

Android Studio では 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();
}
于 2015-08-22T05:44:26.493 に答える
1

検討:

Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...
于 2015-09-09T19:38:21.073 に答える
0

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

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

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

(object1.equals(object2) == true) 場合に限り (object2.equals(object1))

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

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

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

于 2015-01-30T13:42:25.580 に答える
-1

recordId はオブジェクトのプロパティです

@Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Nai_record other = (Nai_record) obj;
        if (recordId == null) {
            if (other.recordId != null)
                return false;
        } else if (!recordId.equals(other.recordId))
            return false;
        return true;
    }
于 2015-08-24T12:16:49.133 に答える