必须一起重写,因为HashMap/HashSet先用hashCode定位桶,再用equals确认相等;若只重写equals,逻辑相等的对象因hashCode不同被散列到不同桶,导致去重失效、get返回null等运行时错误。

面试时讲清楚 equals 与 hashCode 在底层散列表(如 HashMap、HashSet)中的协作原理,关键不是背定义,而是说清“为什么必须一起重写”以及“不这么做会出什么问题”。下面用结构化、贴近真实面试场景的方式组织回答:
散列表怎么靠 hashCode 快速定位?
HashMap 底层是“数组 + 链表/红黑树”。插入或查找一个 key 时,流程是:
- 先调用 key.hashCode(),得到一个 int 值;
- 用这个值对数组长度取模(JDK 8 后是 hash & (table.length - 1)),算出它该落在哪个桶(数组下标);
- 这一步跳过了遍历,直接把查找范围从 O(n) 缩小到单个桶内 —— 这就是 hashCode 的核心价值。
为什么光有 hashCode 不够,还得用 equals?
因为哈希冲突不可避免:不同对象可能算出相同 hashCode(int 只有 2³² 种取值,对象数量远超此数)。所以:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 定位到桶之后,桶里可能已有多个节点(链表或树);
- 这时必须逐个调用 key.equals(现有节点的 key),才能确认是不是同一个逻辑 key;
- 只靠 hashCode 判断相等,会误判;只靠 equals 判断,则完全失去散列表意义。
如果只重写 equals 不重写 hashCode,会发生什么?
举个典型翻车场景:
立即学习“Java免费学习笔记(深入)”;
- 你写了两个内容相同的 User 对象 u1 和 u2(id=100, name="张三"),并重写了 equals 比较 id 和 name;
- 但没重写 hashCode → 它们走 Object 默认实现,大概率返回不同值(比如基于内存地址);
- 把 u1 放进 HashSet,它被存在桶 A;u2 被 put 时算出不同 hash,落到桶 B;
- 结果:set.size() == 2,明明业务上相等,却无法去重;get(u2) 在 HashMap 中也返回 null。
Java 规范里的硬约束是什么?
这不是建议,是契约:
- 强一致性要求:若 a.equals(b) == true,则 a.hashCode() == b.hashCode() 必须成立;
- 反过来说可以不成立:hashCode 相同,equals 可为 false(允许冲突);
- 违反这条,HashMap、HashSet、ConcurrentHashMap 等所有依赖散列的集合行为都会错乱,且问题隐蔽难排查。

















