重写 equals 和 hashcode 必须同时满足自反性、对称性、传递性、一致性与非空性,且逻辑严格对应:相等对象必须有相同 hashcode;需用 objects.equals 和 objects.hash 避免空指针,字段一致、顺序推荐相同,不可变类更安全。

重写 equals 和 hashCode 不是“写对就行”,而是要同时满足一致性、对称性、传递性、自反性和非空性,且二者逻辑必须严格对应——相等的对象必须有相同的 hashCode,这是 HashMap、HashSet 等集合正常工作的前提。
1. 先按规范写 equals:用 Objects.equals 避免空指针
手动判 null + 字段逐个比较易出错。推荐用 java.util.Objects 工具类:
@Override
public boolean equals(Object o) {
if (this == o) return true; // 自反性:自己等于自己
if (o == null || getClass() != o.getClass()) return false; // 类型检查
Person person = (Person) o;
return age == person.age
&& Objects.equals(name, person.name) // 自动处理 null
&& Objects.equals(email, person.email);
}
关键点:
- 先用
==判断引用相同(提升性能且保证自反性) - 必须做
null和类型检查(否则可能 ClassCastException 或 NPE) - 所有参与逻辑相等判断的字段,都要在
equals中比较 - 浮点数慎用
==,建议用Double.compare或Objects.equals
2. hashCode 必须与 equals 保持一致
只要 equals 中用了哪些字段,hashCode 就必须基于**完全相同**的字段计算:
@Override
public int hashCode() {
return Objects.hash(name, email, age); // 顺序要和 equals 中字段顺序一致(非强制但推荐)
}
注意:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
Objects.hash(...)内部调用Objects.hashCode(),自动处理 null,安全简洁 - 不能在
hashCode中使用可变字段(如后期会修改的 List、Map),否则对象放入 HashSet 后修改字段会导致无法查找 - 如果字段是自定义对象,确保其自身已正确重写
hashCode,否则链式失效
3. 使用 IDE 自动生成(推荐但需核对)
IntelliJ / Eclipse 都支持一键生成,但要注意:
- 勾选的字段必须和业务上的“逻辑相等”定义完全一致(比如 ID 是主键?还是 name+email 才唯一?)
- 生成后务必检查是否包含可变字段(如
lastLoginTime这类不该参与相等判断的字段) - 确认没有遗漏关键字段(例如新增了
countryCode却忘了加进 equals/hashCode)
4. 不可变类更安全,优先考虑
如果类设计为不可变(所有字段 final + 无 setter),则 equals/hashCode 天然稳定,不会因对象中途变更导致哈希表失联:
public final class Person {
private final String name;
private final String email;
private final int age;
// 构造器初始化,无修改方法 → 安全可靠
}
若必须可变,请确保:参与 hashCode 的字段在对象加入集合后不再修改。
不复杂但容易忽略:只要改了业务上“什么算相等”的定义,就必须同步更新两个方法,缺一不可。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










