Javaでオブジェクトを比較するときは、セマンティックチェックを行い、オブジェクトのタイプを比較して状態を識別します。
- 自体(同じインスタンス)
- 自体(クローン、または再構築されたコピー)
- 異なるタイプの他のオブジェクト
- 同じタイプの他のオブジェクト
null
ルール:
- 対称性:
a.equals(b) == b.equals(a)
equals()
常に利回りtrue
またはfalse
、決してNullpointerException
、ClassCastException
または任意の他のスロー可能
比較:
- 型チェック:両方のインスタンスは同じ型である必要があります。つまり、実際のクラスが等しいかどうかを比較する必要があります。開発者
instanceof
が型の比較に使用する場合、これは正しく実装されないことがよくあります(サブクラスがない場合にのみ機能し、の場合は対称規則に違反しA extends B -> a instanceof b != b instanceof a)
ます)。
- 状態を識別するセマンティックチェック:インスタンスが識別される状態を理解するようにしてください。人は、社会保障番号で識別できますが、髪の色(染色可能)、名前(変更可能)、または年齢(常に変更)では識別できません。値オブジェクトの場合のみ、完全な状態(すべての非一時フィールド)を比較する必要があります。それ以外の場合は、インスタンスを識別するものだけを確認してください。
あなたのPerson
クラス:
public boolean equals(Object obj) {
// same instance
if (obj == this) {
return true;
}
// null
if (obj == null) {
return false;
}
// type
if (!getClass().equals(obj.getClass())) {
return false;
}
// cast and compare state
Person other = (Person) obj;
return Objects.equals(name, other.name) && Objects.equals(age, other.age);
}
再利用可能な汎用ユーティリティクラス:
public final class Equals {
private Equals() {
// private constructor, no instances allowed
}
/**
* Convenience equals implementation, does the object equality, null and type checking, and comparison of the identifying state
*
* @param instance object instance (where the equals() is implemented)
* @param other other instance to compare to
* @param stateAccessors stateAccessors for state to compare, optional
* @param <T> instance type
* @return true when equals, false otherwise
*/
public static <T> boolean as(T instance, Object other, Function<? super T, Object>... stateAccessors) {
if (instance == null) {
return other == null;
}
if (instance == other) {
return true;
}
if (other == null) {
return false;
}
if (!instance.getClass().equals(other.getClass())) {
return false;
}
if (stateAccessors == null) {
return true;
}
return Stream.of(stateAccessors).allMatch(s -> Objects.equals(s.apply(instance), s.apply((T) other)));
}
}
あなたのためにPerson
クラス、このユーティリティクラスを使用しました:
public boolean equals(Object obj) {
return Equals.as(this, obj, t -> t.name, t -> t.age);
}