大家好,我是小米,一个喜欢分享技术的 29 岁程序员。前两天,有个学弟跟我吐槽,说社招面试题越来越卷了,居然问到 HashSet 的实现原理!他还说:“我明明只用了 new HashSet() 和 add(),怎么要我知道底层实现?”
听完学弟的吐槽,我觉得是时候写一篇通俗易懂的文章,把 HashSet 的实现原理讲清楚,顺便附上面试中的高分回答模板,让大家也能轻松拿下这类题目!
什么是 HashSet?
先从 HashSet 的定义讲起。我们平时使用 HashSet 的场景是为了存储一组 唯一 的元素,类似数学中的集合。比如:
看,HashSet 自动帮我们去重了!是不是很方便?
但这个方便背后,有哪些机制在默默运作呢?
HashSet 的底层是什么?
这里是个知识点:HashSet 是基于 HashMap 实现的。
在源码中,HashSet 其实是一个“壳”,所有的操作最终都委托给了内部的 HashMap 来完成。来看一段 HashSet 的源码(以 JDK 8 为例):
从这段代码我们能看出,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岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!