大家好,我是小米,一个喜欢分享技术的 29 岁程序员。前两天,有个学弟跟我吐槽,说社招面试题越来越卷了,居然问到 HashSet 的实现原理!他还说:“我明明只用了 new HashSet() add(),怎么要我知道底层实现?”

听完学弟的吐槽,我觉得是时候写一篇通俗易懂的文章,把 HashSet 的实现原理讲清楚,顺便附上面试中的高分回答模板,让大家也能轻松拿下这类题目!

什么是 HashSet?

先从 HashSet 的定义讲起。我们平时使用 HashSet 的场景是为了存储一组 唯一 的元素,类似数学中的集合。比如:

面试高频考点:HashSet 的实现原理,一次搞懂!_链表

看,HashSet 自动帮我们去重了!是不是很方便?

但这个方便背后,有哪些机制在默默运作呢?

HashSet 的底层是什么?

这里是个知识点:HashSet 是基于 HashMap 实现的。

在源码中,HashSet 其实是一个“壳”,所有的操作最终都委托给了内部的 HashMap 来完成。来看一段 HashSet 的源码(以 JDK 8 为例):

面试高频考点:HashSet 的实现原理,一次搞懂!_链表_02

从这段代码我们能看出,HashSet 的本质是一个特殊的 HashMap:它只存储键(Key),不存储值(Value)。

在 HashMap 中,每个键值对是 Key-Value 的形式,而 HashSet 则将所有值固定为一个虚拟常量 PRESENT,实现了只存储键的效果。

HashSet 的实现原理详解

1. 添加元素时如何保证唯一性?

要理解 HashSet 去重的秘密,我们必须先搞懂 HashMap 的 put() 方法

HashMap 的底层是一个数组 + 链表 + 红黑树的结构。具体步骤如下:

  • 计算哈希值
  • 当你调用 add() 方法时,HashSet 会把元素传给 HashMap 的 put() 方法。
  • HashMap 首先通过 hash() 方法计算出元素的哈希值,用于确定该元素存储的位置(桶索引)。
  • 找到存储桶
  • 根据哈希值找到数组中的存储桶。如果桶里已经有元素,则会遍历链表或树,比较这些元素。
  • 通过 equals() 判断重复
  • 如果新元素的 hashCode() 和 equals() 方法都与已有元素匹配,则认为是重复的,直接返回。
  • 如果不重复,则将新元素插入链表或红黑树中。

所以,HashSet 的唯一性,依赖于元素的 hashCode() 和 equals() 方法!

2. 查找和删除的效率如何?

HashSet 的查找和删除效率非常高,平均时间复杂度为 O(1)。这是因为:

  • 查找时直接通过哈希值定位到数组的存储桶;
  • 如果桶内有多个元素(哈希冲突),则在链表中遍历或在红黑树中查找,最坏复杂度为 O(log n)。

3. 扩容机制是怎样的?

HashSet 的扩容同样依赖于 HashMap。当存储的元素数量超过一定阈值(默认容量的 75%)时,HashMap 会触发扩容:

  • 数组容量翻倍;
  • 重新计算所有元素的哈希值,并将它们分布到新的桶中。

面试高分回答模板

如果面试官问你 HashSet 的实现原理,可以参考以下回答:

HashSet 是基于 HashMap 实现的,它的本质是一个只存储键(Key)的 HashMap。添加元素时,HashSet 会通过哈希值和 equals() 方法判断是否重复,以保证唯一性。

底层采用数组 + 链表 + 红黑树的结构,平均时间复杂度为 O(1)。当哈希冲突较多时,链表会转化为红黑树,查找复杂度降为 O(log n)。同时,HashSet 支持动态扩容,保证性能的稳定性。

加分项:

  • 提到 hashCode() 和 equals() 方法的重要性;
  • 描述扩容机制。

学弟的面试翻盘之路

讲完这些,学弟一拍大腿:“原来如此!不过面试官还问我,HashSet 和 TreeSet 有啥区别,我又答不上来。”

哈哈,其实这个问题更简单了!

HashSet 和 TreeSet 的区别

  • 底层结构不同
  • HashSet 基于 HashMap,底层是哈希表。
  • TreeSet 基于 TreeMap,底层是红黑树。
  • 排序特性
  • HashSet 中的元素是无序的。
  • TreeSet 会自动对元素进行排序(基于自然顺序或自定义比较器)。
  • 性能差异
  • HashSet 的增删查操作平均时间复杂度为 O(1)。
  • TreeSet 的增删查操作时间复杂度为 O(log n)。

END

相信看到这里,你已经对 HashSet 的实现原理有了深刻的理解。在面试中,如果还能提到 HashSet 和 TreeSet 的区别,面试官一定会对你的细致和全面印象深刻!

如果你有其他关于 Java 集合框架的问题,欢迎在评论区留言,我们一起探讨!

小米的问答时光机

下一篇想聊聊 ArrayList 和 LinkedList 的区别?还是 ConcurrentHashMap 的并发机制?留言告诉我吧!

我是小米,一个喜欢分享技术的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号软件求生,获取更多技术干货!