Java里的equals方法应该如何重写_对象判等规则解析

重写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(),否则子类实例可能错误地等于父类实例,破

坏对称性和传递性。

必须同步重写 hashCode 方法

只要两个对象 equals 返回 true,它们的 hashCode 就必须相同。否则放入 HashMapHashSet 时会找不到对象。

建议使用 Objects.hash(...) 生成哈希码,字段顺序和 equals 中的判断顺序保持一致:

@Override
public int hashCode() {
    return Objects.hash(name, age);
}

常见错误与规避方式

  • 忘记判空或类型检查 → 导致 NullPointerException 或不对称结果
  • equals 中修改对象状态 → 违反一致性契约
  • 使用浮点数直接 == 比较 → 应改用 Double.compare 或设定误差范围
  • 忽略继承场景 → 若类可被继承,需谨慎设计(通常建议类声明为 final,或使用组合代替继承)