java equals()メソッドのオーバーライド-動作していませんか?
-
06-07-2019 - |
質問
今日、 equals()
メソッドで興味深い(非常にイライラする)問題が発生しました。これにより、十分にテストされたクラスと思われるものがクラッシュし、バグが発生しました。追跡に時間がかかります。
完全を期すために、私はIDEやデバッガーを使用していませんでした。古き良き時代のテキストエディターとSystem.outだけです。時間は非常に限られており、学校のプロジェクトでした。
とにかく-
Book
オブジェクトの ArrayList
を含むことができる基本的なショッピングカートを開発していました。カートの addBook()
、 removeBook()
、および hasBook()
メソッドを実装するために、< code> Book は既に Cart
に存在していました。じゃあ行って-
public boolean equals(Book b) {
... // More code here - null checks
if (b.getID() == this.getID()) return true;
else return false;
}
テストではすべて正常に動作します。 6つのオブジェクトを作成し、それらにデータを入力します。 Cart
で多くの追加、削除、has()操作を行うと、すべてが正常に機能します。 equals(TYPE var)
または equals(Object o){(CAST)var}
のいずれかを使用できることを読みましたが、働いていた、それはあまり重要ではなかった。
その後、問題に遭遇しました-Bookクラス内から ID
のみを 含む Book
オブジェクトを作成する必要がありました。他のデータは入力されません。基本的に次のとおりです。
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つのデータメンバーのみで満たされているように思われます。私はとても混乱しています。光を当ててください。
解決
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
アノテーションの使用は、愚かな間違いのトンを助けることができます。
スーパークラスまたはインターフェースのメソッドをオーバーライドしていると思う場合はいつでも使用してください。そうすれば、間違えるとコンパイルエラーが発生します。
他のヒント
Eclipseを使用する場合は、トップメニューに移動してください
出典-&gt; equals()を生成し、 hashCode()
あなたの質問から少し外れていますが、とにかく言及する価値があるでしょう:
Commons Lang には、equalsとhashcodeのオーバーライドに使用できるいくつかの優れたメソッドがあります。 EqualsBuilder.reflectionEquals(...)および HashCodeBuilder.reflectionHashCode(...)。過去にたくさんの頭痛の種を救いました-もちろん、「等しい」をしたいだけならIDでは、状況に合わない場合があります。
また、等しい(または他のメソッド)をオーバーライドするときはいつでも @Override
アノテーションを使用する必要があることに同意します。
定型コードを保存する別の高速ソリューションは、 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;
オプションをご覧になり、同等で使用するフィールドをカスタマイズしてください。 Lombokは maven で利用できます。 提供スコープで追加するだけです:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.14.8</version>
<scope>provided</scope>
</dependency>
Android Studioでは alt + insert ---&gt;等しいおよび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();
}
検討:
Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...
instanceOf
ステートメントは、equalsの実装でよく使用されます。
これはよくある落とし穴です!
問題は、 instanceOf
を使用すると対称性の規則に違反することです。
(object1.equals(object2)== true)
次の場合にのみ (object2.equals(object1))
最初の等号が真であり、object2がサブクラスのインスタンスである場合 obj1が属するクラスの場合、2番目のequalsはfalseを返します!
ob1が属するとみなされるクラスがfinalとして宣言されている場合、これ 問題は発生しませんが、一般に、次のようにテストする必要があります。
this.getClass()!= otherObject.getClass();
そうでない場合はfalseを返し、そうでない場合はテストする
等しいかどうかを比較するフィールド!
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;
}