java基础的面试高频04:equals 和 hashCode 为什么要配套重写?不重写 HashMap 会出现什么严重问题

equals()和hashCode()是 Object 类中两个顶级方法,几乎所有集合面试都会围绕这两个方法展开。很多同学只记住一句话:相等的对象必须哈希值相等,哈希值相等对象不一定相等,却答不出为什么必须成对重写,不重写在HashMap、HashSet中会出现什么 bug。今天结合哈希表底层原理讲清楚设计规范。

一、原生 equals 与 hashCode 默认实现

1. Object 原生 equals 方法

默认实现是使用==比较两个对象的内存地址,只有两个引用指向堆中同一个对象时才返回 true,无法实现我们自定义的 “业务相等”。

比如用户类,我们希望两个用户 id 相同就判定为同一个用户,原生 equals 无法实现,必须重写。

2. Object 原生 hashCode 方法

根据对象的内存地址,通过哈希算法生成一个 int 类型哈希值,不同对象地址不同,哈希值大概率不同。

二、为什么必须配套重写 equals 和 hashCode?

Java 官方约定两条通用规范:

  • 如果两个对象通过equals()相等,那么两个对象的hashCode()返回值必须相等;
  • 如果两个对象 hashCode 相等,equals 不一定相等(哈希碰撞)。

只重写 equals,不重写 hashCode 会发生什么?

两个业务上相等的对象,equals 返回 true,但 hashCode 基于内存地址生成,哈希值不一样。

当存入HashSet、HashMap时:
哈希表会先判断哈希值是否相同,哈希值不同会直接判定为两个不同对象,最终导致两个业务相同的对象都被存入集合,集合去重失效。

只重写 hashCode,不重写 equals 会发生什么?

两个对象哈希值相同,发生哈希碰撞后,会调用 equals 判断是否为同一个对象;如果使用原生 equals 对比内存地址,最终依旧判定为两个不同对象,同样无法实现去重。

三、结合 HashMap 底层详解失效场景

HashMap 存储键值对时的执行流程:

  1. 根据 key 的 hashCode 计算数组下标;

  2. 如果下标位置没有元素,直接存入;

  3. 如果下标已有元素(哈希碰撞),调用equals判断 key 是否完全相等;

  4. equals 相等则覆盖旧 value,不相等则挂载到链表 / 红黑树。

举个例子:自定义 User 类,只重写 equals,根据 userId 判定相等,没有重写 hashCode:

  1. user1 和 user2 的 userId 相同,equals 返回 true;

  2. 两个对象内存地址不同,原生 hashCode 返回不同数值;

  3. put 进 HashMap 时,两个 key 会落在哈希表不同下标位置,最终两个相同业务 key 同时存入,出现重复 key。

四、正确重写规范

  1. 业务相等的属性同时用于 equals 判断和 hashCode 哈希计算;

  2. 推荐使用 IDE 自动生成 equals 和 hashCode 方法(基于业务唯一字段);

  3. 重写 equals 时一定要加@Override注解,避免方法签名写错。

面试高频总结

  • 重写 equals 必须重写 hashCode,目的是保证相等对象哈希值一致,满足哈希表去重规则;

  • HashSet 底层基于 HashMap 实现,元素不可重复依赖 hashCode+equals 双重校验;

  • 哈希碰撞:不同对象 hashCode 相同,此时需要 equals 做二次精准校验。

posted @ 2026-07-01 23:01  桃桃不淘1  阅读(0)  评论(0)    收藏  举报