重写 equals 方法是为了实现逻辑相等而非地址比较,且必须同时重写 hashCode 以保证哈希集合正确性;需遵守自反性、对称性、传递性、一致性及对 null 处理五项约定,并按标准步骤使用 getClass() 和 Objects.equals 安全比较字段。

重写 equals 方法是为了让两个对象在“逻辑上相等”时返回 true,而不是默认的内存地址比较。Java 中必须同时重写 hashCode,否则可能破坏哈希集合(如 HashMap、HashSet)的正确性。
1. 遵守 equals 的通用约定
Java 规范要求 equals 方法必须满足以下五点:
-
自反性:对任意非 null 引用
x,x.equals(x)必须返回true -
对称性:若
x.equals(y)为true,则y.equals(x)也必须为true -
传递性:若
x.equals(y)和y.equals(z)都为true,则x.equals(z)也应为true - 一致性:多次调用结果不变(除非参与比较的字段被修改)
-
对 null 的处理:对任意非 null 引用
x,x.equals(null)必须返回false
2. 标准重写步骤(推荐模板)
以一个简单的 Person 类为例:
public class Person {
private String name;
private int age;
// 构造方法、getter 省略...
@Override
public boolean equals(Object obj) {
// 1. 判断是否为同一对象(提高性能)
if (this == obj) return true;
// 2. 判断是否为 null 或类型不匹配
if (obj == null || getClass() != obj.getClass()) return false;
// 3. 强转为具体类型
Person person = (Person) obj;
// 4. 比较关键字段(注意 null 安全)
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
说明:
立即学习“Java免费学习笔记(深入)”;
- 用
getClass() != obj.getClass()而不是!(obj instanceof Person),可避免子类打破对称性 - 字段比较优先使用
Objects.equals(a, b),它能安全处理null - 基本类型(如
int、boolean)直接用==;引用类型务必用Objects.equals
3. 常见错误与避坑点
以下写法看似合理,实则违反约定或引发问题:
-
忘记重写
hashCode:会导致对象在HashMap中无法被正确查到 -
参数类型写成
Person而非Object:这不是重写,是重载,毫无作用 -
用
instanceof判断类型 + 允许父类与子类相等:易导致对称性或传递性失败(如Student extends Person) - 比较了不该参与逻辑相等的字段(如数据库 ID、创建时间、缓存字段),会使语义混乱
-
在
equals中抛出异常或执行耗时操作(如 I/O、远程调用)
4. 工具辅助(可选但推荐)
现代 IDE(IntelliJ IDEA、Eclipse)都支持自动生成 equals 和 hashCode 方法,只需右键 → Generate → equals() and hashCode(),勾选要参与比较的字段即可。生成结果符合规范,且自动使用 Objects 工具类。
如果项目使用 Lombok,可直接加注解:
@EqualsAndHashCode
public class Person {
private String name;
private int age;
}
它会在编译期生成标准实现,简洁安全。


















