hashset底层基于hashmap实现,元素作为key存入,value统一为present对象;add、remove、contains等操作均委托给hashmap,时间复杂度平均o(1);迭代器遍历其keyset,故无序且不保证插入顺序。

HashSet 底层确实基于 HashMap 实现,但它并不直接暴露 HashMap 的键值对语义,而是巧妙地复用其数据结构来支持“无序、不重复”的集合行为。
核心思路:只用 HashMap 的 key,value 固定为一个空对象
HashSet 内部持有一个 transient HashMapmap),所有元素都作为 key 存入该 HashMap,而 value 统一使用一个静态的、不可变的占位对象:PRESENT(类型是 Object,实际就是一个 new Object() 的常量引用)。
这样做的好处是:完全复用 HashMap 的哈希计算、数组+链表/红黑树存储、扩容机制、冲突处理等全部能力,同时规避了 value 管理的开销。
add() 方法本质是 map.put(key, PRESENT)
当你调用 set.add("abc") 时,HashSet 实际执行的是:
- 调用内部 HashMap 的
put("abc", PRESENT) - 如果 key 之前不存在,put 返回 null → add() 返回 true
- 如果 key 已存在,put 返回旧的 PRESENT → add() 返回 false
所以“是否重复”的判断,完全由 HashMap 的 key 去重逻辑(equals() + hashCode())保证,HashSet 本身不额外做比较。
remove() 和 contains() 同理,委托给 HashMap
set.remove("abc") → 调用 map.remove("abc"),返回值是否为 PRESENT 决定是否成功set.contains("abc") → 调用 map.containsKey("abc"),直接查 key 是否存在
这些操作的时间复杂度和 HashMap 一致:平均 O(1),最坏 O(n)(哈希全冲突且未树化时)。
迭代器遍历的是 HashMap 的 keySet
HashSet 的 iterator() 返回的是内部 HashMap 的 keySet().iterator()。所以你遍历 HashSet,本质上是在遍历 HashMap 所有 key 构成的视图 —— 这也解释了为什么 HashSet 是无序的(取决于 HashMap 桶中 key 的存放顺序),且不能保证插入顺序(除非用 LinkedHashSet,它背后是 LinkedHashMap)。
注意:keySet 是 HashMap 的一个内部视图,不额外拷贝数据,因此 HashSet 的迭代也是轻量的。
不复杂但容易忽略:HashSet 的线程不安全、允许 null(因为 HashMap 允许一个 null key)、以及所有约束都继承自 HashMap 的实现细节。











