HashSet底层基于HashMap实现,将元素作为key、统一Object对象作为value,利用HashMap的键唯一性保障元素不重复,所有操作均委托给HashMap完成。

HashSet 底层就是用 HashMap 实现的,它不存真正的“值”,而是把每个元素作为 HashMap 的 key,统一用一个固定的 Object 对象(比如 PRESSENT)作为 value。
为什么能用 HashMap 实现 HashSet
HashSet 的核心要求是:元素唯一、不保证顺序、支持快速查找和增删。这些特性 HashMap 天然满足——key 不允许重复、底层是哈希表、平均时间复杂度 O(1)。所以 JDK 设计者直接复用 HashMap,避免重复造轮子。
关键点:
- HashSet 中的每个元素,都映射为 HashMap 的一个 key
- 所有 key 对应的 value 都是同一个静态对象:
private static final Object PRESENT = new Object(); - HashMap 的 key 判断是否重复,依赖
hashCode()和equals(),HashSet 也完全继承这一套逻辑
add() 方法是怎么工作的
调用 HashSet.add(e) 时,实际执行的是:
立即学习“Java免费学习笔记(深入)”;
// 简化后的逻辑map.put(e, PRESENT);
如果 key 已存在,put() 返回旧 value(即 PRESENT),HashSet 就知道这个元素已存在,返回 false;否则插入成功,返回 true。
也就是说,add 的“去重”行为,完全是 HashMap put 的副产物。
其他操作也都是委托给 HashMap
HashSet 几乎所有操作都只是对内部 HashMap 的简单封装:
-
contains(e)→ 调用map.containsKey(e) -
remove(e)→ 调用map.remove(e) -
size()→ 返回map.size() -
iterator()→ 遍历的是map.keySet().iterator()
连迭代器遍历的顺序,都取决于 HashMap 的 keySet 迭代顺序(JDK 8 后是桶+红黑树/链表的混合顺序,非严格插入序)。
注意:HashSet 不是线程安全的
因为底层用的是普通 HashMap,不是 ConcurrentHashMap。多线程并发读写 HashSet 会出问题。如需线程安全,可使用:
Collections.synchronizedSet(new HashSet())- 或
new CopyOnWriteArraySet()(适合读多写少)
但它们都不是基于 ConcurrentHashMap 实现的——Java 并没有提供“ConcurrentHashSet”,因为并发场景下通常需要更明确的行为控制(比如是否允许重复添加、如何处理冲突),单纯去重往往不够。


















