
重写 equals() 方法时,首要检查 this == o 是为了确保自反性(reflexivity)——即任何非 null 对象必须与自身相等,这是 Java 合约的强制要求;忽略此检查可能导致 NaN、null 字段或特殊状态对象违反该原则。
重写 `equals()` 方法时,首要检查 `this == o` 是为了确保自反性(reflexivity)——即任何非 null 对象必须与自身相等,这是 java 合约的强制要求;忽略此检查可能导致 `nan`、`null` 字段或特殊状态对象违反该原则。
在 Java 中,Object.equals() 方法的语义契约明确规定:对于任意非 null 引用 x,x.equals(x) 必须返回 true(自反性)。这是 equals() 方法正确实现的基石,也是 HashSet、HashMap 等集合类正常工作的前提。若省略 if (this == o) return true; 这一快速路径,看似“节省代码”,实则埋下严重隐患。
最典型的反例是包含 double 或 float 类型字段的类:
public class Product {
private double price;
private String name;
@Override
public boolean equals(Object o) {
if (!(o instanceof Product)) return false;
Product p = (Product) o;
// ❌ 危险:未处理 NaN 场景
return price == p.price && Objects.equals(name, p.name);
}
}当 price 为 Double.NaN 时,NaN == NaN 的结果是 false(IEEE 754 规定),导致 product.equals(product) 返回 false —— 直接违反自反性,可能引发集合操作异常(如 map.get(product) 查不到自身插入的键)。
此外,该检查还带来两项关键收益:
- 性能优化:引用相等(==)是最快判断,避免后续类型检查、字段比较等开销;
- 空安全兜底:虽然 this 不可能为 null,但若后续逻辑依赖 this 的非空状态(如调用 this.name.equals(...)),此检查也间接规避了潜在空指针风险(尽管非主因)。
✅ 正确写法(含完整合约保障):
@Override
public boolean equals(Object o) {
if (this == o) return true; // ✅ 自反性 + 性能
if (o == null || getClass() != o.getClass()) // ✅ null 安全 + 类型严格(优于 instanceof)
return false;
Menu menu = (Menu) o;
return Double.compare(price, menu.price) == 0 // ✅ 安全比较 double(处理 NaN)
&& Objects.equals(name, menu.name);
}⚠️ 注意事项:
- 优先使用 getClass() != o.getClass() 替代 !(o instanceof Menu),可避免违反对称性(子类误认为父类实例相等);
- 对于浮点数字段,务必用 Double.compare(a, b) == 0 或 Float.compare(a, b) == 0,而非 ==;
- 配套重写 hashCode(),且保证:equals() 返回 true 的两个对象,其 hashCode() 值必须相同。
总之,this == o 不是“冗余代码”,而是守护 equals() 合约的第一道防线——它用一行简洁逻辑,同时保障语义正确性、运行时健壮性与基础性能。

















