今日、equals()
メソッドに関する興味深い(そして非常にイライラする)問題に遭遇しました。
完全を期すために、私はIDEやデバッガーを使用していませんでした-古き良き時代のテキストエディターとSystem.outだけです。時間は非常に限られており、学校のプロジェクトでした。
とにかく-
ArrayList
of Book
オブジェクトを含むことができる基本的なショッピングカートを開発していました。 CartのaddBook()
、removeBook()
、hasBook()
メソッドを実装するために、Book
がCart
に既に存在するかどうかを確認したいと思いました。だから私は行く-
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つのデータメンバーのみで満たされているように思われます。私はとても混乱しています。光を当ててください。
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を使用している場合は、トップメニューに移動します
ソース-> 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;
イコールで使用するフィールドをカスタマイズするには、 options を参照してください。 Lombokは maven で利用可能です。 providedスコープで追加するだけです:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.14.8</version>
<scope>provided</scope>
</dependency>
考慮してください:
Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...
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();
}
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を返し、そうでない場合はフィールドをテストして同等かどうかを比較します!