linkedhashmap 默认按插入顺序维护双向链表,启用 accessorder=true 后改为访问顺序(lru);其 entry 同时属于哈希表和链表,兼顾 o(1) 查找与有序迭代。

LinkedHashMap 确实用双向链表维护顺序,但具体维护哪一种顺序,取决于构造参数。
插入顺序是默认行为
如果不指定 accessOrder = false(即使用默认构造或只传 initialCapacity/loadFactor 的构造函数),LinkedHashMap 会按元素**插入的先后顺序**在双向链表中排列。遍历时(如 keySet()、entrySet() 迭代),得到的就是插入顺序。
- put 新元素 → 链表尾部追加
- put 已存在 key → 不改变链表顺序(除非启用了 accessOrder)
- remove 某个 entry → 同时从哈希表和链表中移除,保持链表连贯
访问顺序需显式开启
只有当构造时传入 true 作为第三个参数(accessOrder),LinkedHashMap 才会按**最近访问(get/put 更新已有 key)的顺序**重排链表:每次访问某个 entry,它会被移到链表尾部。
- 启用后,get(key) 或 put(key, value)(key 已存在)都会触发该 entry 移至链表末尾
- 这种模式天然适合实现 LRU 缓存:链表头部是最久未使用的项,可直接淘汰
- 注意:put 新 key 仍是在尾部新增,不是“访问”,所以不触发移动已有节点
双向链表与哈希表协同工作
每个 LinkedHashMap.Entry 同时是哈希桶中的节点,又通过 before 和 after 引用嵌入双向链表。这样既保有 HashMap 的 O(1) 查找效率,又支持 O(1) 的链表插入/删除/移动操作。
- 哈希表负责定位:根据 key 的 hash 值快速找到对应桶和节点
- 双向链表负责排序:所有节点按序串在一起,迭代时无需遍历整个哈希表
- 两个结构通过同一个 Entry 实例耦合,内存上紧凑,逻辑上正交
实际使用注意点
顺序行为只影响迭代顺序,不影响 get/put 的时间复杂度,也不改变哈希表本身的结构。
- 不要依赖 toString() 或 debugger 显示的顺序来判断是否启用 accessOrder —— 要看构造方式
- 如果需要稳定插入顺序且不允许重复 key,LinkedHashMap 比 HashMap + ArrayList 组合更简洁、更安全
- 实现 LRU 时,建议覆写 removeEldestEntry(),配合 accessOrder=true 自动清理链表头部










