重写equals方法必须严格遵循自反性、对称性、传递性、一致性和对null处理五大契约,同步重写hashCode,使用Objects.equals和Objects.hash确保空安全与一致性,避免instanceof导致的继承问题。

重写 equals 方法不是简单地比较字段值,而是要遵循一套明确的契约规则,否则可能引发集合操作异常、哈希表失效等隐蔽问题。
必须遵守的五个核心契约
Java 规范要求 equals 方法必须满足以下五点,缺一不可:
-
自反性:对任意非 null 对象 x,
x.equals(x)必须返回true -
对称性:对任意非 null 对象 x 和 y,
x.equals(y)返回true当且仅当y.equals(x)也返回true -
传递性:对任意非 null 对象 x、y、z,若
x.equals(y)和y.equals(z)均为true,则x.equals(z)也必须为true -
一致性:多次调用
x.equals(y)(对象状态未变)结果必须一致 -
对 null 的处理:对任意非 null 对象 x,
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(),否则子类实例可能错误地等于父类实例,破坏对称性和传递性。
立即学习“Java免费学习笔记(深入)”;
必须同步重写 hashCode 方法
只要两个对象 equals 返回 true,它们的 hashCode 就必须相同。否则放入 HashMap、HashSet 时会找不到对象。
建议使用 Objects.hash(...) 生成哈希码,字段顺序和 equals 中的判断顺序保持一致:
@Override
public int hashCode() {
return Objects.hash(name, age);
}
常见错误与规避方式
- 忘记判空或类型检查 → 导致
NullPointerException或不对称结果 - 在
equals中修改对象状态 → 违反一致性契约 - 使用浮点数直接 == 比较 → 应改用
Double.compare或设定误差范围 - 忽略继承场景 → 若类可被继承,需谨慎设计(通常建议类声明为
final,或使用组合代替继承)










