重写equals方法必须严格遵循自反性、对称性、传递性、一致性和对null处理五大契约,同步重写hashCode,使用Objects.equals和Objects.hash确保空安全与一致性,避免instanceof导致的继承问题。
重写 equals 方法不是简单地比较字段值,而是要遵循一套明确的契约规则,否则可能引发集合操作异常、哈希表失效等隐蔽问题。
Java 规范要求 equals 方法必须满足以下五点,缺一不可:
x.equals(x) 必须返回 true
x.equals(y) 返回 true 当且仅当 y.equals(x) 也返回 true
x.equals(y) 和 y.equals(z) 均为 true,则 x.equals(z) 也必须为 true
x.equals(y)(对象状态未变)结果必须一致x.equals(null) 必须返回 false
推荐使用 Objects.equals() 简化空安全比较,避免手动判
null。典型结构如下:
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // 引用相等,快速返回
if (obj == null || getClass() != obj.getClass()) // 类型检查,防止跨类误判
return false;
Person person = (Person) obj; // 安全强转
return age == person.age && // 基本类型直接 ==
Objects.equals(name, person.name); // 引用类型用 Objects.equals
}
注意:不要用 instanceof 替代 getClass() != obj.getClass(),否则子类实例可能错误地等于父类实例,破坏对称性和传递性。
只要两个对象 equals 返回 true,它们的 hashCode 就必须相同。否则放入 HashMap、HashSet 时会找不到对象。
建议使用 Objects.hash(...) 生成哈希码,字段顺序和 equals 中的判断顺序保持一致:
@Override
public int hashCode() {
return Objects.hash(name, age);
}
NullPointerException 或不对称结果equals 中修改对象状态 → 违反一致性契约Double.compare 或设定误差范围final,或使用组合代替继承)