Java中如何实现按插入顺序保存键值对

来源:建站技术作者:小诸葛头衔:草根站长
导读:本期聚焦于小伙伴创作的《Java中如何实现按插入顺序保存键值对》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java中如何实现按插入顺序保存键值对》有用,将其分享出去将是对创作者最好的鼓励。

在Java的集合框架中,HashMap是最常用的键值对存储结构,但它内部的元素是无序的,遍历时无法保证和插入顺序一致。如果需要实现按插入顺序保存键值对的需求,LinkedHashMap就是最合适的选择,它在HashMap的基础上做了扩展,完美解决了顺序问题。

Java中如何实现按插入顺序保存键值对

LinkedHashMap的基本原理

LinkedHashMap继承自HashMap,它在HashMap的数组+链表+红黑树结构基础上,额外维护了一个双向链表。这个双向链表的作用就是记录所有键值对的插入顺序,每次插入新元素或者访问已有元素时,都会调整这个双向链表的结构,从而保证遍历的时候可以按照插入的先后顺序输出元素。

LinkedHashMap的核心属性有两个:

  • head:指向双向链表的头节点,也就是最早插入的元素
  • tail:指向双向链表的尾节点,也就是最晚插入的元素

核心构造方法说明

LinkedHashMap提供了多个构造方法,最常用的是无参构造和带初始容量、负载因子的构造方法,默认情况下都是按照插入顺序维护链表:

import java.util.LinkedHashMap;
import java.util.Map;

public class LinkedHashMapDemo {
    public static void main(String[] args) {
        // 无参构造,默认初始容量16,负载因子0.75,按插入顺序排序
        LinkedHashMap<String, Integer> map1 = new LinkedHashMap<>();
        
        // 自定义初始容量和负载因子的构造方法
        LinkedHashMap<String, Integer> map2 = new LinkedHashMap<>(32, 0.8f);
        
        // 第三个参数accessOrder为true时,会按照访问顺序排序,false为插入顺序
        LinkedHashMap<String, Integer> map3 = new LinkedHashMap<>(16, 0.75f, false);
    }
}

插入顺序的实现逻辑

LinkedHashMap重写了HashMap的newNode方法,在创建新节点的时候,会把节点加入到双向链表的末尾:

// LinkedHashMap的内部节点类,继承自HashMap的Node,增加了before和after指针
static class Entry<K,V> extends HashMap.Node<K,V> {
    Entry<K,V> before, after;
    Entry(int hash, K key, V value, Node<K,V> next) {
        super(hash, key, value, next);
    }
}

// 重写newNode方法,创建节点后加入双向链表尾部
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
    Entry<K,V> p = new Entry<>(hash, key, value, e);
    // 把新节点加入双向链表尾部
    linkNodeLast(p);
    return p;
}

// 维护双向链表的逻辑
private void linkNodeLast(Entry<K,V> p) {
    Entry<K,V> last = tail;
    tail = p;
    if (last == null)
        head = p;
    else {
        p.before = last;
        last.after = p;
    }
}

当遍历LinkedHashMap的时候,它不会去遍历HashMap底层的哈希数组,而是直接遍历这个双向链表,从头节点开始依次访问每个节点,自然就保证了顺序和插入顺序一致。

和HashMap的对比

我们可以通过一个简单示例对比两者的顺序差异:

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

public class CompareDemo {
    public static void main(String[] args) {
        // 使用HashMap存储
        Map<String, Integer> hashMap = new HashMap<>();
        hashMap.put("a", 1);
        hashMap.put("b", 2);
        hashMap.put("c", 3);
        System.out.println("HashMap遍历结果:");
        for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        
        // 使用LinkedHashMap存储
        Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
        linkedHashMap.put("a", 1);
        linkedHashMap.put("b", 2);
        linkedHashMap.put("c", 3);
        System.out.println("LinkedHashMap遍历结果:");
        for (Map.Entry<String, Integer> entry : linkedHashMap.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
}

运行上述代码可以看到,HashMap的遍历顺序是不固定的,而LinkedHashMap的遍历顺序一定是a、b、c,和插入顺序完全一致。

访问顺序模式说明

LinkedHashMap还有一个特殊的访问顺序模式,当构造方法的accessOrder参数设为true时,每次访问一个元素(包括get和put已存在的键),都会把这个元素移动到双向链表的尾部,这时候遍历顺序就是访问顺序,最近访问的元素会在最后面。这个特性可以用来实现简单的LRU缓存:

import java.util.LinkedHashMap;
import java.util.Map;

public class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private int maxSize;
    
    public LRUCache(int maxSize) {
        // 设置accessOrder为true,开启访问顺序模式
        super(16, 0.75f, true);
        this.maxSize = maxSize;
    }
    
    // 重写removeEldestEntry方法,当元素数量超过最大值时,移除最老的元素(头节点)
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > maxSize;
    }
    
    public static void main(String[] args) {
        LRUCache<String, Integer> cache = new LRUCache<>(2);
        cache.put("a", 1);
        cache.put("b", 2);
        // 访问a,a会被移动到尾部
        cache.get("a");
        // 插入c,此时最老的元素是b,会被移除
        cache.put("c", 3);
        System.out.println(cache); // 输出 {a=1, c=3}
    }
}

使用注意事项

  • LinkedHashMap的查询、插入、删除操作的时间复杂度和HashMap基本一致,只是多了维护双向链表的开销,性能略低一点,但顺序特性带来的收益通常更大
  • 如果需要保证插入顺序,构造LinkedHashMap时不要把accessOrder设为true,默认是false,也就是插入顺序模式
  • LinkedHashMap是线程不安全的,如果需要多线程环境下使用,需要额外做同步处理,或者使用Collections.synchronizedMap包装

JavaLinkedHashMap键值对插入顺序修改时间:2026-07-24 14:21:32

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。