Javaでのequals()メソッドとhashCode()メソッドのオーバーライド
Equals
および は、hashCode
クラス内で宣言されObject
、標準 Java ライブラリに含まれる基本的なメソッドです。 このメソッドは、オブジェクトを比較し、オブジェクトの整数コードを生成するためеquals()
に使用されます。hashCode
これらのメソッドは、 にオブジェクトを挿入および取得するときに Java 標準ライブラリで広く使用されていますHashMap
。このメソッドは、一意のオブジェクトのみが他の実装equal
に格納されるようにするためや、オブジェクトを比較する必要があるその他の場合にも使用されます。クラス内のメソッドのデフォルト実装は、変数が格納するメモリ アドレスへの参照を比較し、アドレスが一致する場合、つまり変数が同じオブジェクトを参照する場合にのみ返します。Java では、比較が自然なロジックまたはビジネス ロジックに従うことが予想される場合、およびメソッドをオーバーライドすることをお勧めします。標準 Java ライブラリの多くのクラスはこれらをオーバーライドします。たとえば、このクラスは、比較される 2 つのオブジェクトの内容が同じである場合に返すようにオーバーライドします。ラッパー クラスはメソッドをオーバーライドして数値比較などを実行します。Java はとメソッドにも依存してと を比較するため、Java はこれらのメソッドをオーバーライドするための次のルールを提供します。 HashSet
Set
equals()
java.lang.Object
true
equals()
hashCode()
String
equals
true
Integer
equal
HashMap
HashTable
equals()
hashCode()
key
values
- 反射性: オブジェクトはそれ自体と等しくなければなりません。
- 対称:
a.equals(b)
を返す場合はtrue
、 もb.equals(a)
返さなければなりませんtrue
。 - 推移性:
a.equals(b)
を返しtrue
、b.equals(c)
さらに を返す場合はtrue
、c.equals(a)
も返さなければなりませんtrue
。 - 一貫性: メソッドの繰り返し呼び出しは、
equals()
オブジェクトのプロパティ値の一部が変更されない限り、同じ値を返す必要があります。つまり、Java で 2 つのオブジェクトが等しい場合、それらのプロパティが変更されない限り、それらは等しいことになります。 - 比較
null
: オブジェクトをチェックする必要がありますnull
。オブジェクトが に等しい場合null
、メソッドはfalse
ではなくを返す必要がありますNullPointerException
。たとえば、a.equals(null)
を返す必要がありますfalse
。
JavaにおけるequalsとhashCodeの間の合意
- メソッドの実行結果においてオブジェクトが等しい場合
equals
、それらはhashcode
同じである必要があります。 - メソッドの実行結果においてオブジェクトが等しくない場合
equals
、それらはhashcode
同じであることも、異なることもあり得ます。ただし、パフォーマンスを向上させるには、異なるオブジェクトが異なるコードを返すようにすることをお勧めします。
Javaでequalsメソッドをオーバーライドする方法
-
@Override public boolean equals(Object obj) { /*1. Check*/
if (obj == this) { /*and return */ return true; }
-
オブジェクトに があるかどうかを確認し
null
、オブジェクトが同じタイプであることも確認してください。instanceof
これはサブクラスに対して返されtrue
、クラスが として宣言されている場合にのみ正しく動作するため、 をチェックしないでくださいimmutable
。getClass()
;を使用できます。if (obj == null || obj.getClass() != this.getClass()) { return false; }
-
比較する型の変数を宣言し、
obj
その型にキャストします。次に、数値属性の方がより速くチェックされるため、数値属性 (存在する場合) から始めて各タイプ属性を比較します。AND 演算子と OR 演算子 ( と呼ばれるshort-circuit logical operators
) を使用して属性を比較し、チェックを他の属性と組み合わせます。Person guest = (Person) obj; return id == guest.id && (firstName == guest.firstName || (firstName != null && firstName.equals(guest.getFirstName()))) && (lastName == guest.lastName || (lastName != null && lastName .equals(guest.getLastName()))); }
/** * Person class with equals and hashcode implementation in Java * @author Javin Paul */
public class Person {
private int id;
private String firstName;
private String lastName;
public int getId() { return id; }
public void setId(int id) { this.id = id;}
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
Person guest = (Person) obj;
return id == guest.id
&& (firstName == guest.firstName
|| (firstName != null &&firstName.equals(guest.getFirstName()))) && (lastName == guest.lastName
|| (lastName != null && lastName .equals(guest.getLastName())
));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((firstName == null) ? 0 : firstName.hashCode()); result = prime * result + id; result = prime * result +
((lastName == null) ? 0 : lastName.hashCode()); return result;
}
}
Javaでequalsをオーバーライドする際のよくある間違い
-
クラス内のメソッドの構文は次のように定義されていますが、多くのプログラマーは、クラスの名前を引数として使用する代わりに(例: Person) 、誤ってメソッドをオーバーロードして
equals (Override)
しまいます。このエラーは、 により検出が困難です。したがって、クラスのオブジェクトに対してこのメソッドを呼び出すと、メソッドはコンパイルされるだけでなく、正しくコンパイルされます。ただし、たとえばオブジェクトをコレクションに入れ、その操作がメソッドに基づいているメソッドを呼び出す場合、そのメソッドはオブジェクトを検出できません。(Overload)
equals()
Object
public boolean equals(Object obj)
public boolean equals(Person obj)
Object
static binding
ArrayList
contains()
equals()
contains
-
メソッドをオーバーライドするときは、変数
equals()
をチェックしないでください。最終的には を呼び出すときにチェックされます。以下は正しいコードです。null
NullPointerException
equals()
firstname == guest.firstname || (firstname != null && firstname.equals(guest.firstname));
-
3 番目のよくある間違いは、メソッドをオーバーライドせず
hashCode()
、equals()
. Java でもequals()
両方のメソッドをオーバーライドする必要があります。hashCode()
このメソッドは-collections (たとえば、 )hashCode
で使用され、衝突が少ないほど (異なるオブジェクトに同じコードが使用されるほど)、これらのコレクションはクラスのオブジェクトでより効率的に機能します。hash
HashSet
-
プログラマが犯す最後のよくある間違いは、メソッドをオーバーライドするときに、
equals()
メソッドequals()
とメソッド間のマッピングが保持されないことですcompareTo()
。これは、 に重複を格納することを避けるための非公式の要件ですSet (SortedSet, TreeSet)
。
Javaでequalsメソッドを記述する方法のヒント
-
NetBeans、Eclipse、IntelliJ IDEA などのほとんどの IDE は、メソッド
equals()
との生成をサポートしていますhashCode()
。Eclipse では、右クリック -> ソース ->generate equals()
と を選択しますhashCode()
。 -
クラスに一意のビジネス キーがある場合は、これらのフィールドが等しいかどうかだけをチェックするだけで十分です。この例のように、「id」は各人に固有の番号です。
-
Java でオーバーライドする場合は
hashCode()
、メソッドで使用されたすべてのフィールドを必ず使用してくださいequals()
。 -
String
および などのラッパー クラスはInteger
メソッドをオーバーライドしますFloat
が、オーバーライドしません。Double
equals()
StringBuffer
-
可能な限り、Java の変数
immutable
を使用してフィールドを作成します。final
-
オブジェクトを比較する場合は
String
、equals()
代わりに . 演算子を使用します==
。 -
論理的には等しいが、異なるオブジェクトからロードされた 2 つのオブジェクトは
ClassLoader
等しくありません。ローダークラスが異なる場合は、 でチェックすると結果getClass()
が返されることに注意してください。false
-
@Override
. メソッドでもアノテーションを使用するhashCode
と、 の戻り値などの微妙なエラーが防止されますint
。ただし、一部のプログラマは . を返しますlong
。
GO TO FULL VERSION