以下是 HashSet 的底层原理的详细解析,结合数据结构、哈希冲突处理、扩容机制及线程安全性等核心要点:
一、底层实现:基于 HashMap 的包装类
HashSet 的底层通过 HashMap 实现,所有元素均存储为 HashMap 的键(Key),而值(Value)统一使用一个静态常量 PRESENT(private static final Object PRESENT = new Object())占位。这种设计使得 HashSet 的元素唯一性完全依赖 HashMap 的键不可重复特性。
数据结构示意图:
HashSet 实例
└── 内部 HashMap
├── 数组 (Buckets)
│ ├── 索引0 → 链表/红黑树节点(元素1 → 元素2 → ...)
│ ├── 索引1 → null
│ ├── 索引2 → 红黑树根节点(元素3 → ...)
│ └── ...
└── 负载因子(默认 0.75)、容量(默认 16)
二、核心操作流程
1. 添加元素(add(e))
• 哈希值计算:调用元素的 hashCode() 方法生成哈希码,再通过哈希函数 (h = key.hashCode()) ^ (h >>> 16) 计算最终哈希值。
• 确定桶位置:哈希值对数组长度取模((n-1) & hash),确定元素应存放的桶索引。
• 冲突处理:
• 桶为空:直接插入新节点。
• 桶为链表:遍历链表,通过 equals() 判断是否重复。若无重复,插入链表尾部;若链表长度≥8且数组长度≥64,链表转为红黑树。
• 桶为红黑树:调用红黑树插入逻辑,确保元素唯一性。
2. 删除元素(remove(o))
• 通过哈希值定位桶,遍历链表或红黑树找到目标节点,调整指针移除节点。若红黑树节点数≤6,退化为链表。
3. 查询元素(contains(o))
• 哈希值定位桶后,遍历链表或红黑树,通过 equals() 判断是否存在目标元素。
三、构造方法与扩容机制
1. 构造方法
• 默认构造器:初始化容量为 16,负载因子 0.75。
• 指定容量/负载因子:直接传递参数至内部 HashMap。
• 基于集合构造:初始容量为 Math.max(集合大小 / 0.75 + 1, 16),避免频繁扩容。

最低0.47元/天 解锁文章
2146

被折叠的 条评论
为什么被折叠?



