linkedhashmap 保证插入或访问顺序,hashmap 不保证;前者支持 lru 缓存、可预测遍历,后者无序但稍快;两者序列化后 linkedhashmap 顺序可保持,但跨语言/协议时顺序不保障。

LinkedHashMap 保证插入顺序,HashMap 不保证
这是最直观也最容易被忽略的差异。当你用 put() 逐个插入键值对,LinkedHashMap 迭代时(比如用 entrySet().iterator())会严格按插入顺序返回;而 HashMap 的迭代顺序是不确定的,取决于哈希值、扩容时机和内部桶结构,哪怕插入顺序相同,不同 JVM 或不同版本也可能表现不同。
- 适用场景:需要“最近插入优先遍历”(如缓存写入日志)、或调试时依赖可预测的遍历顺序,选
LinkedHashMap - 注意:
LinkedHashMap的顺序不是线程安全的;并发修改下仍可能抛ConcurrentModificationException -
HashMap在 JDK 8 后对链表过长会转红黑树,但不改变其无序本质
LinkedHashMap 可以按访问顺序排序(LRU 缓存基础)
LinkedHashMap 提供了带 accessOrder 参数的构造函数:new LinkedHashMap(16, 0.75f, true)。设为 true 后,每次 get() 或 put() 已存在 key,对应节点会被移到链表尾部——这就构成了 LRU(Least Recently Used)行为的基础。
-
HashMap完全没有访问顺序概念,get()不改变内部结构 - 想手动实现 LRU,用
LinkedHashMap重写removeEldestEntry()是标准做法,比自己维护双链表+哈希表简单可靠 - 注意:启用
accessOrder = true后,keySet()和values()迭代也按访问顺序,不只是entrySet()
内存开销与性能差异实际很小,但有明确代价
LinkedHashMap 每个节点除了哈希桶指针,还额外维护前驱/后继引用,因此单个 Entry 占用更多内存(通常多 16–24 字节),且插入/删除操作要同步更新双向链表。
- 在百万级数据下,内存差异一般不超过 5%,多数业务场景可忽略
- 纯随机写入场景,
LinkedHashMap插入耗时略高(约 10–15%),但差距远小于一次 GC 停顿 - 如果只读多、写少,且需要顺序,
LinkedHashMap几乎无额外运行时成本 - 别为了“理论上更快”盲目换
HashMap——顺序需求没满足,bug 可能更贵
序列化行为一致,但反序列化后顺序可能“失效”
两者都实现了 Serializable,序列化内容都包含容量、负载因子、键值对列表。但关键点在于:LinkedHashMap 序列化时会把链表顺序一并写出,反序列化后顺序得以保留;而 HashMap 反序列化后仍是无序的。
立即学习“Java免费学习笔记(深入)”;
- 不过要注意:如果你用
ObjectOutputStream写出再用不同 JDK 版本读取,LinkedHashMap的顺序仍能保持,但某些自定义序列化逻辑(如 JSON 库)可能忽略链表信息,只当普通 Map 处理 - Gson / Jackson 默认把
LinkedHashMap当作Map序列化,不保留顺序;需显式注册类型适配器或改用TreeMap等可预测顺序的替代方案 - 别假设“用了
LinkedHashMap就永远有序”——跨进程、跨语言、跨序列化协议时,顺序保障边界很窄










