必须遵守“相等对象哈希码必须相等”的契约,否则HashMap、HashSet会出现查不到、重复添加等运行时错误;核心要求是:equals为true则hashCode必相同,hashCode不同则equals必为false,且同一对象多次调用hashCode结果须一致。

重写 equals 和 hashCode 必须遵守“相等对象必须具有相等哈希码”的契约,否则在 HashMap、HashSet 等集合中会出现逻辑错误——比如对象明明存在却查不到、重复添加等。
equals 与 hashCode 的核心契约
Java 规范明确要求:
- 如果两个对象通过
equals比较返回true,那么它们的hashCode必须返回相同整数 - 如果两个对象的
hashCode不同,equals一定不能返回true(即哈希码不同是“不相等”的充分条件) -
hashCode在同一对象生命周期内多次调用应返回相同值(前提是未修改影响 equals 的字段)
重写时必须同步处理的字段
只对参与 equals 判定的字段计算 hashCode,反之亦然。常见错误是:equals 比较了 name 和 age,但 hashCode 只用了 name。
推荐做法:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
立即学习“Java免费学习笔记(深入)”;
- 使用 IDE 自动生成(如 IntelliJ 的
Alt+Insert→ “Generate” → “equals() and hashCode()”),它会自动保持字段一致 - 手动编写时,先列出所有用于 equals 的非静态、非 transient 字段,再在两个方法中严格使用相同子集
- 注意 null 安全:用
Objects.equals(a, b)和Objects.hash(f1, f2, ...),它们天然处理 null
违反契约的实际后果
不是编译报错,而是运行时集合行为异常:
- 对象存入
HashSet后,若修改了影响hashCode的字段,该对象再也无法被remove或contains找到(因为哈希桶位置已变) - 在
HashMap中作为 key 使用时,若hashCode不稳定,可能导致同一个 key 被当作多个不同 key 存储,引发数据丢失或重复 - 即使
equals正确,只要hashCode不满足契约,集合类就无法正常工作
不可变性是最省心的解法
如果类设计允许,把参与 equals 判定的字段设为 final,构造时初始化,之后不再修改:
- 天然满足
hashCode稳定性要求 - 避免因字段变更导致集合失效的隐蔽 bug
- 线程安全、语义清晰,也更符合函数式编程思想
例如:ID、用户名、邮箱等标识性字段适合设为 final;而状态类(如 UserStatus)若需频繁更新,则应避免用作集合 key,或改用其他唯一不变标识。

















