Java中的LinkedHashMap源码分析

 更新时间:2023年12月15日 08:42:29   作者:爱喝咖啡的程序员  
这篇文章主要介绍了Java中的LinkedHashMap源码分析,LinkedHashMap是HashMap的子类,所以基本的操作与hashmap类似,不过呢,在插入、删除、替换key-value对的时候,需要的朋友可以参考下

一. 基本原理和优缺点

LinkedHashMap能记录你插入元素的顺序,在遍历时,能按照插入的顺序给你遍历出来。

LinkedHashMap是HashMap的子类,所以基本的操作与hashmap类似。不过呢,在插入、删除、替换key-value对的时候,LinkedHashMap会维护一个链表结构,专门用来记录key-value对的顺序。当我们遍历LinkedHashMap时,就能按照顺序把key-value来遍历出来。

所以啊,别看LinkedHashMap的名字中带有Linked,其实它的底层仍然是数组实现的。

当删除元素时,它会在双向链表的尾部删除节点,当查询元素时,实际上是在迭代双向链表,从头节点开始迭代。用于维护双向链表的顺序。

这里面有一个非常核心的参数: accessOrder。

二. 源码分析

2.1 put(K key, V value) 初次插入

绝大部分代码逻辑与hashmap完全一样,只不过,LinkedHashMap自己重写了newNode()方法。

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;
}

将节点封装成了LinkedHashMap.Entry对象,然后使用linkNodeLast()挂载节点。

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内部维护了两个指针head和tail,分别指向顺序链表的头结点和尾结点。

每当我们向LinkedHashMap内新增一个key-value,就会在顺序链表的末尾挂载一个顺序节点。这个挂载的过程其实就是对双向链表新增一个节点。

2.2 put(K key, V value) 覆盖已经存在的key

如果LinkedHashMap中已经插入了key1-value1,此时我们插入key1-value2,会产生什么后果呢?

答案是,key1在LinkedHashMap内的插入顺序保持不变,但是value被覆盖。

关于覆盖的操作,由于我们熟悉HashMap的源码,所以立刻可以锁定到hashmap的putVal()内如下代码块:

if (e != null) { // existing mapping for key
	V oldValue = e.value;
	if (!onlyIfAbsent || oldValue == null)
		e.value = value;
	afterNodeAccess(e);
	return oldValue;
}

如果在插入之前,能找到这个key对应的节点,那么就用新的value覆盖这个节点内的旧value,接着执行afterNodeAccess(e)。

注意,LinkedHashMap重写了afterNodeAccess(e)。

void afterNodeAccess(Node<K,V> e) { // move node to last
	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;
		p.after = null;
		if (b == null)
			head = a;
		else
			b.after = a;
		if (a != null)
			a.before = b;
		else
			last = b;
		if (last == null)
			head = p;
		else {
			p.before = last;
			last.after = p;
		}
		tail = p;
		++modCount;
	}
}

LinkedHashMap有一个非常重要的参数,accessOrder ,它可以通过入参,经过构造函数传入LinkedHashMap。accessOrder默认等于false,这就意味着,你覆盖或者查询这个key,都不会改变key在链表里的顺序。当它等于true时,就截然相反了,每当你覆盖或者查询这个key,LinkedHashMap就会把这个key挪动到顺序链表的末尾。

2.3 remove

大部分的逻辑仍然走的是hashmap的removeNode(),只不过LinkedHashMap重写了afterNodeRemoval( )。

void afterNodeRemoval(Node<K,V> e) { // unlink
	LinkedHashMap.Entry<K,V> p =
		(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
	p.before = p.after = null;
	if (b == null)
		head = a;
	else
		b.after = a;
	if (a == null)
		tail = b;
	else
		a.before = b;
}

到此这篇关于Java中的LinkedHashMap源码分析的文章就介绍到这了,更多相关LinkedHashMap源码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java实现注册登录系统

    java实现注册登录系统

    这篇文章主要为大家详细介绍了java实现注册登录系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • Java 详细分析四个经典链表面试题

    Java 详细分析四个经典链表面试题

    兄弟们,编程,当我们学习完数据结构的时候,你就会有一种豁然开朗的感觉。算是真正的入了编程的门,所以打好数据结构的基础是特别特别重要的
    2022-03-03
  • java Thread 多线程

    java Thread 多线程

    本篇文章小编为大家介绍,java Thread 多线程。需要的朋友参考下
    2013-04-04
  • Spring Boot整合Swagger测试api构建全纪录

    Spring Boot整合Swagger测试api构建全纪录

    这篇文章主要给大家介绍了关于Spring Boot整合Swagger测试api构建的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • Java中生成不重复随机数的四种方法举例详解

    Java中生成不重复随机数的四种方法举例详解

    在Java编程中获取随机数是常见的需求,这篇文章主要介绍了Java中生成不重复随机数的四种方法,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-04-04
  • 优雅地在Java 8中处理异常的方法详解

    优雅地在Java 8中处理异常的方法详解

    异常处理是我们在日常开发中经常会遇到的一种需求,下面这篇文章主要给大家介绍了关于如何优雅地在Java 8中处理异常的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们来一起看看吧
    2019-01-01
  • java中归并排序和Master公式详解

    java中归并排序和Master公式详解

    大家好,本篇文章主要讲的是java中归并排序和Master公式详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2022-01-01
  • 深入分析JAVA Synchronized关键字

    深入分析JAVA Synchronized关键字

    这篇文章主要介绍了析JAVA Synchronized关键字的相关知识,文中代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-06-06
  • 详解spring cloud如何使用spring-test进行单元测试

    详解spring cloud如何使用spring-test进行单元测试

    这篇文章主要介绍了spring cloud如何使用spring-test进行单元测试,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Java面试题冲刺第十六天--消息队列

    Java面试题冲刺第十六天--消息队列

    这篇文章主要为大家分享了最有价值的三道关于消息队列的面试题,涵盖内容全面,包括数据结构和算法相关的题目、经典面试编程题等,感兴趣的小伙伴们可以参考一下
    2021-08-08

最新评论