hashset底层用hashmap的key存元素,value固定为present占位符;复用hashmap已优化的哈希冲突处理、扩容机制等,专注去重语义。

HashSet 底层其实不直接存储元素,而是把所有元素作为 HashMap 的 key 来存,value 固定用一个共享的空对象(PRESENT)占位。
为什么用 HashMap 而不是自己实现哈希表?
复用已有的、经过充分测试和优化的 HashMap 实现,避免重复造轮子。HashMap 已经解决了哈希冲突(拉链法 + 红黑树)、扩容机制、线程安全(非同步)、负载因子控制等核心问题。HashSet 只需专注“去重”这一语义,其余全交给 HashMap 处理。
关键设计:统一 value 占位符
HashSet 内部定义了一个 static final Object 类型的常量:private static final Object PRESENT = new Object();
每次调用 add(e) 时,实际执行的是:map.put(e, PRESENT)
由于 HashMap 的 key 不允许重复,put 同一个 key 会覆盖旧 value(但 value 始终是同一个 PRESENT),自然就实现了“添加不重复元素”的语义。
操作如何映射到 HashMap?
-
add(e) →
map.put(e, PRESENT),返回值是前一个 value(null 表示新增,非 null 表示已存在) -
contains(e) →
map.containsKey(e),直接查 key 是否存在 -
remove(e) →
map.remove(e),删掉对应 key -
size() →
map.size(),因为每个 key 对应一个唯一元素 -
迭代器遍历 → 实际遍历的是
map.keySet().iterator()
注意点:HashSet 的“无序”和“不可靠”
它继承了 HashMap 的迭代顺序特性:不保证插入顺序(JDK 8 之前完全无序),也不保证任何稳定顺序;若需有序,得用 LinkedHashSet(底层用 LinkedHashMap)或 TreeSet(底层用 TreeMap)。另外,HashSet 非线程安全,多线程写入需外部同步。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











