必须同时重写equals和hashCode方法,因为哈希表依赖hashCode定位桶、equals精确判等;若仅重写equals,逻辑相等对象可能散列到不同桶,导致查找失败、重复存储、去重失效。

因为哈希表类(如 HashMap、HashSet)依赖 hashCode 定位桶位置,再用 equals 精确判等;如果只重写 equals 而不重写 hashCode,逻辑相等的对象可能散列到不同桶中,导致查不到、存重复、去重失效。
哈希容器的查找机制决定了二者必须一致
HashMap 和 HashSet 底层是数组 + 链表/红黑树结构。插入或查询时分两步:
- 先调用对象的 hashCode(),算出它该落在哪个数组索引(即“桶”)里
- 若该桶已有元素,再用 equals() 逐个比对,确认是否为同一逻辑对象
如果 a.equals(b) == true,但 a.hashCode() != b.hashCode(),它们就会被放进不同桶——后续调用 map.get(b) 或 set.contains(b) 就永远找不到 a,哪怕内容一模一样。
Java 规范明确要求这一契约
Object 类文档和《Effective Java》都强调:只要 equals 返回 true,hashCode 就必须返回相同值。这不是建议,而是强制约定。违反它会直接破坏集合行为:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
- HashSet 存入重复对象:两个业务上相等的实例被当作不同元素加入
- HashMap 查不到已存键:用新构造的等价对象 get,返回 null
- ConcurrentHashMap、LinkedHashSet 同样受影响:底层仍基于哈希定位
重写时的关键实操原则
二者必须基于同一组字段计算,且兼顾安全与一致性:
- equals 中用于比较的字段(如 name、age),hashCode 也必须参与运算
- 推荐用 IDE 自动生成(IntelliJ 按 Alt+Insert → “equals and hashCode”),避免漏字段
- 注意 null 安全:字段可能为 null,优先用
Objects.hashCode(field),别直接调field.hashCode() - 不要在 hashCode 中使用可变字段——对象加入 HashSet 后修改该字段,就再也找不到了
一个典型反例说明问题
Person 类只重写了 equals(按 name 和 age 判断相等),但没改 hashCode:
Person p1 = new Person("Alice", 25);Person p2 = new Person("Alice", 25);-
p1.equals(p2)返回 true -
p1.hashCode() == p2.hashCode()却是 false(用的是 Object 默认实现) -
set.add(p1); set.contains(p2)返回 false —— 本该是 true!

















