linkedhashmap 默认按插入顺序维护元素,底层通过双向链表实现,新节点始终追加至链表尾部;启用 accessorder=true 时转为访问顺序(lru),get 或 put 已存在 key 会将对应节点移至尾部。

LinkedHashMap 是 HashMap 的子类,它通过维护一个双向链表来记录元素的顺序。默认情况下,它按插入顺序排列键值对;但可以通过构造参数启用访问顺序(即最近最少使用 LRU 行为)。这是它和 HashMap 最核心的区别。
如何按插入顺序维护(默认行为)
不传入特殊参数时,LinkedHashMap 自动保持你 put 元素的先后顺序。遍历(如用 for-each 或迭代器)时,会严格按照插入顺序返回。
- 直接使用无参构造:`new LinkedHashMap()`
- 或显式指定初始容量、加载因子:`new LinkedHashMap(16, 0.75f)`
- 插入后遍历输出,顺序与 put 一致
例如:
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
// 遍历时输出 a→b→c
如何按访问顺序维护(启用 LRU)
只需在构造时将第三个布尔参数设为 true,即可开启访问顺序模式。此时每次 get 或 put 已存在 key 时,对应节点会被移到链表尾部;迭代时从头到尾就是“最久未使用 → 最近使用”。
- 构造方式:`new LinkedHashMap(16, 0.75f, true)`
- put 新 key 仍插入尾部;put 已存在 key 或 get 某 key,都会触发该 entry 移至尾部
- 适合实现缓存淘汰逻辑(配合重写 removeEldestEntry)
配合 removeEldestEntry 实现自动淘汰
LinkedHashMap 提供了可重写的方法 `removeEldestEntry(Map.Entry)`,在每次 put 后被调用。返回 true 就会自动删除最老的条目(链表头部)。
- 常用于限制缓存大小,比如只保留最近 100 个访问项
- 需注意:只有在访问顺序模式下,这个“最老”才代表“最久未使用”
- 示例:重写后当 size > 100 时返回 true,即可实现固定容量 LRU 缓存
注意事项和常见误区
- LinkedHashMap 不是线程安全的,多线程需外部同步(如 Collections.synchronizedMap)或改用 ConcurrentLinkedHashMap 等第三方实现
- accessOrder 为 true 时,key 的“访问”仅指 get 和 put(已存在 key),put 新 key 不算访问,只是插入
- entrySet()、keySet()、values() 返回的集合都继承插入/访问顺序,但它们的 iterator 仍是 O(1) 时间复杂度,链表开销很小
- 不要误以为它比 HashMap 慢很多——实际性能差距微小,除非极端高频操作
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











