LinkedHashSet通过封装LinkedHashMap实现插入顺序维护,其元素作为key、PRESENT为value存于LinkedHashMap中,复用后者基于哈希表加双向链表(含before/after指针)的结构,插入时追加至链表尾部,重复添加不改变位置,迭代即遍历该链表。

LinkedHashSet 通过内部封装的 LinkedHashMap 实现插入顺序维护,它本身不直接操作双向链表,而是复用 LinkedHashMap 的底层机制——后者在哈希表基础上额外维护了一条双向链表,用于记录元素插入时的先后关系。
LinkedHashSet 底层其实是 LinkedHashMap
LinkedHashSet 没有独立的存储结构,它的所有添加、删除、遍历操作都委托给内部一个 LinkedHashMap 实例。这个 map 的 key 就是 LinkedHashSet 中的元素,value 固定为一个静态的 PRESENT 对象(只是一个占位符)。所以“维护插入顺序”这件事,实际由 LinkedHashMap 完成。
- LinkedHashMap 继承自 HashMap,保留了数组 + 链表/红黑树的哈希结构用于快速查找
- 同时,它为每个 Entry(Node)增加了 before 和 after 引用,构成一条按插入顺序连接的双向链表
- 每次调用 put(key, value) 时,新节点不仅插入哈希桶中,还会被追加到双向链表尾部
双向链表节点如何串联
LinkedHashMap 的内部节点类(LinkedHashMap.Entry)继承自 HashMap.Node,并新增两个字段:
- before:指向前一个插入的节点
- after:指向后一个插入的节点
- 维护两个哨兵节点:head(链表头,最早插入)和 tail(链表尾,最近插入)
- 插入新元素时,新节点的 before 指向当前 tail,tail.after 指向新节点,然后 tail 更新为新节点
这样就保证了迭代器从 head 到 tail 遍历时,顺序严格等于插入顺序。
立即学习“Java免费学习笔记(深入)”;
为什么重复添加不会改变链表顺序
当 add() 一个已存在的元素时,LinkedHashSet 调用 LinkedHashMap 的 put() 方法:
- 哈希计算定位到已有节点,直接更新 value(但 value 始终是 PRESENT,无实质变化)
- LinkedHashMap 默认 不移动节点位置(accessOrder = false),即不调整双向链表结构
- 所以原节点在链表中的位置保持不变,插入顺序不受影响
迭代过程就是遍历双向链表
LinkedHashSet.iterator() 返回的是 LinkedHashMap.KeyIterator,其核心逻辑是:
- 从 head 节点开始
- 不断调用 next = e.after 获取下一个节点
- 直到 next == null 为止
- 整个过程绕过了哈希数组的杂乱布局,只走插入时建立的链路
这正是为什么 for-each 或 iterator 遍历 LinkedHashSet 总是按插入顺序输出——它本质上是在遍历一条手工维护的、保序的双向链表。


















