在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);
}