在Java中LinkedHashMap的有序特性如何实现

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

在Java集合体系中,LinkedHashMap是HashMap的一个子类,它最大的特点就是能够保持元素的顺序,而普通的HashMap在遍历时元素的顺序是不固定的。这种有序特性并不是通过额外的排序逻辑实现的,而是基于底层的数据结构扩展。

在Java中LinkedHashMap的有序特性如何实现

LinkedHashMap的底层结构

LinkedHashMap继承自HashMap,因此它的底层存储依然是基于数组+链表+红黑树的结构,和HashMap完全一致。除此之外,LinkedHashMap额外维护了一个双向链表,这个链表的作用就是记录所有元素的顺序。我们可以看一下LinkedHashMap中定义的几个关键字段:

// 双向链表的头节点,指向顺序最靠前的元素
transient LinkedHashMap_Entry<K,V> head;

// 双向链表的尾节点,指向顺序最靠后的元素
transient LinkedHashMap_Entry<K,V> tail;

// 访问顺序开关,true表示按访问顺序排序,false表示按插入顺序排序,默认是false
final boolean accessOrder;

其中LinkedHashMap_Entry是LinkedHashMap的内部类,它继承自HashMap的Node类,额外增加了before和after两个指针,用来维护双向链表的前后关系:

static class LinkedHashMap_Entry<K,V> extends HashMap_Node<K,V> {
    LinkedHashMap_Entry<K,V> before, after;
    LinkedHashMap_Entry(int hash, K key, V value, Node<K,V> next) {
        super(hash, key, value, next);
    }
}

插入顺序的实现逻辑

当accessOrder为false时,LinkedHashMap按照元素的插入顺序维护双向链表。在插入新元素的时候,LinkedHashMap会重写HashMap的newNode方法,在创建节点之后,将新节点加入到双向链表的尾部:

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

// 将节点链接到双向链表尾部
private void linkNodeLast(LinkedHashMap_Entry<K,V> p) {
    LinkedHashMap_Entry<K,V> last = tail;
    tail = p;
    // 如果链表为空,头节点也指向当前节点
    if (last == null)
        head = p;
    else {
        // 否则将当前节点链接到原尾节点之后
        p.before = last;
        last.after = p;
    }
}

当遍历LinkedHashMap的时候,它不会去遍历底层的HashMap数组,而是直接遍历这个双向链表,从头节点开始依次访问after指针指向的节点,因此遍历的顺序就是元素插入的顺序。

访问顺序的实现逻辑

当accessOrder设置为true时,LinkedHashMap会按照元素的访问顺序维护双向链表,最近被访问的元素会被移动到双向链表的尾部。这个逻辑是通过重写HashMap的afterNodeAccess方法实现的,这个方法会在调用get方法访问元素之后被触发:

// 重写get方法,当accessOrder为true时,访问后调整节点顺序
public V get(Object key) {
    Node<K,V> e;
    if ((e = getNode(hash(key), key)) == null)
        return null;
    // 如果开启访问顺序,访问后调整节点位置
    if (accessOrder)
        afterNodeAccess(e);
    return e.value;
}

// 访问节点后将节点移动到双向链表尾部
void afterNodeAccess(Node<K,V> e) {
    LinkedHashMap_Entry<K,V> last;
    // 如果当前节点不是尾节点,才需要调整
    if (accessOrder && (last = tail) != e) {
        LinkedHashMap_Entry<K,V> p =
            (LinkedHashMap_Entry<K,V>)e, b = p.before, a = p.after;
        // 先断开当前节点的after指针
        p.after = null;
        // 如果当前节点是头节点,将头节点指向它的下一个节点
        if (b == null)
            head = a;
        else
            b.after = a;
        // 如果当前节点不是尾节点,将它的下一个节点的before指向它的上一个节点
        if (a != null)
            a.before = b;
        else
            last = b;
        // 将当前节点链接到双向链表尾部
        if (last == null)
            head = p;
        else {
            p.before = last;
            last.after = p;
        }
        tail = p;
    }
}

这种访问顺序的特性可以用来实现简单的LRU缓存,只需要继承LinkedHashMap,重写removeEldestEntry方法,当元素数量超过阈值时移除最久未访问的元素即可。

两种顺序模式的对比

我们可以通过一个表格来对比两种顺序模式的区别:

顺序模式accessOrder值顺序规则触发顺序调整的操作
插入顺序false(默认)元素按照插入的先后顺序排列,先插入的在前,后插入的在后插入新元素时调整
访问顺序true最近被访问的元素排在最后,最久未访问的元素排在最前插入新元素、调用get方法访问元素时调整

使用注意事项

  • LinkedHashMap因为额外维护了双向链表,所以内存占用会比普通的HashMap更高,在不需要顺序特性的场景下不建议使用。
  • 插入顺序模式下,修改已存在元素的value值不会改变元素的顺序,只有插入新元素和访问操作(开启访问顺序时)才会调整顺序。
  • LinkedHashMap不是线程安全的,多线程环境下如果需要使用,需要额外做同步处理,或者使用Collections.synchronizedMap包装。
需要注意的是,LinkedHashMap的有序特性是基于双向链表实现的,和TreeMap的排序逻辑完全不同,TreeMap是通过比较器或者键的自然顺序来排序的,而LinkedHashMap只是记录插入或者访问的先后顺序,不会对键进行排序。

LinkedHashMapJava有序特性HashMap双向链表修改时间:2026-07-16 16:39:35

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