返回顶部
首页 > 资讯 > 后端开发 > Python >源码解析带你了解LinkedHashMap
  • 701
分享到

源码解析带你了解LinkedHashMap

2024-04-02 19:04:59 701人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录元素存储关系继承体系属性构造方法无参有参按插入顺序访问newnodelinkNodeLast链表节点的删除LRU(Least recently used,最近最少使用)栗子元素被

LinkedHashMap维护插入的顺序。

元素存储关系

红黄箭头:元素添加顺序
蓝箭头:单链表各个元素的存储顺序
head:链表头部
tail:链表尾部

继承体系

  • 继承自 HashMap ,因此 HashMap 拥有的荣耀它也都有.

5088755_1577812744625_DA615EAF7757A05A68BDC4C9093BBBD8

属性

  • 双向链表的头(最老)

  • 双链表的末尾(最小)

  • HashMap.Node的子类:常规 LinkedHashMap 节点,增加了 before 和 after 属性,维护双向链表的结构

此 LinkedHashMap 的迭代排序方法:

  • true: 访问顺序
  • false(默认): 插入顺序

构造方法

构造方法都是先执行父类 HashMap 的构造方法.

无参

  • 构造一个空的维护插入顺序的LinkedHashMap实例,其默认初始容量(16)和负载因子(0.75).

有参

  • 构造一个空的LinkedHashMap实例,可自己指定初始容量,负载因子和排序模式.

  • 构造一个维护插入顺序的LinkedHashMap实例,该实例具有与指定map相同的映射关系,创建的LinkedHashMap实例具有默认的加载因子(0.75)和足以容纳指定map中映射的初始容量.

下面我们开始研究该类的主要特性是如何通过代码实现的.

按插入顺序访问

LinkedHashMap 默认 accessOrder 为 false,提供按照插入顺序的访问,并没有重写父类 HashMap 的 put 方法.但在 HashMap 中,put 的是 HashMap 的 Node 类型节点,LinkedHashMap 的 Entry 与其结构并不同,又是怎样建立起双向链表的呢?下面一起看下 LinkedHashMap 插入相关代码.

忽略未重写的 put=>putValue代码部分,我们直接观察重写的

newNode

  • HashMap

  • LinkedHashMap 重写

控制新增节点追加到链表的尾部,这样每次新节点都追加到尾部,即可保证插入顺序了.
继续研究 linkNodeLast

linkNodeLast

新增节点,并追加到链表的尾部.


`// link at the end of list`

`private` `void` `linkNodeLast(LinkedHashMap.Entry<K,V> p) {`

`LinkedHashMap.Entry<K,V> last = tail;`

`// 新增于尾节点`

`tail = p;`

`// last 为null,说明链表为空`

`if` `(last == ``null``)`

`head = p;`

`// 链表非空,建立新节点和上一个尾节点的前后关系`

`else` `{`

`// 将新节点 p 直接接在链尾`

`p.before = last;`

`last.after = p;`

`}`

`}`

由此得知,通过在 HashMap 基础上新增的头尾节点,节点的 before 和 after 属性,就能实现在每次新增时,把节点直接追加到尾节点,即可达到维护按照插入顺序的链表结构的目的!

  • 图解链表创建步骤

蓝色部分是 HashMap 的方法
橙色部分为 LinkedHashMap 独有方法

注意 LinkedHashMap 虽然也是双向链表,但只提供单向的按插入的顺序从头到尾访问,不及 LinkedList 般可双向无死角访问.

  • LinkedHashMap 通过迭代器访问,而且默认是从头节点开始访问

迭代过程中,不断访问 after 节点即可完成遍历.

1 处进行校验
2 处通过节点的 after 属性,找到后继节点

链表节点的删除

  • HashMap 中保存的允许 LinkedHashMap 后处理的回调

与插入操作一样,LinkedHashMap 删除操作相关的代码也是直接用父类的实现. 在删除节点时,父类不会修复 LinkedHashMap 的双向链表。那么删除及节点后,被删除的节点该如何从双链表中安全移除呢?其实在删除节点后,回调方法 afterNodeRemoval 会被调用。LinkedHashMap 重写了该方法.


`// e 为已经删除的节点`

`void` `afterNodeRemoval(Node<K,V> e) { ``// unlink`

`LinkedHashMap.Entry<K,V> p =`

`(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;`

`// 将 p 节点的前驱后后继引用置 null,辅助 GC`

`p.before = p.after = ``null``;`

`// p.before 为 null,表明 p 是头节点`

`if` `(b == ``null``)`

`head = a;`

`else`

`// 否则将 p 的前驱节点连接到 p 的后继节点`

`b.after = a;`

`// a 为 null,表明 p 是尾节点`

`if` `(a == ``null``)`

`tail = b;`

`else`

`// 否则将 a 的前驱节点连接到 b`

`a.before = b;`

`}`

删除元素的主要流程:

  • 根据 hash 定位到桶位置
  • 遍历链表或调用红黑树相关的删除方法
  • 从 LinkedHashMap 维护的双链表中移除要删除的节点

5088755_1583897219283_48356470140921DD4FA1E2C40982DE97

转存失败重新上传取消

LRU(Least recently used,最近最少使用)

栗子

经常访问的元素会被追加到队尾,这样不经常访问的数据自然就靠近队头,然后可以通过设置删除策略,比如当 Map 元素个数大于多少时,把头节点删除

元素被移到队尾

get 时,元素会被移动到队尾:


`public` `V get(Object key) {`

`Node<K,V> e;`

`// 调用 HashMap  get 方法`

`if` `((e = getNode(hash(key), key)) == ``null``)`

`return` `null``;`

`// 如果设置了 LRU 策略`

`if` `(accessOrder)`

`// 这个方法把当前 key 移动到队尾`

`afterNodeAccess(e);`

`return` `e.value;`

`}`

从上述源码中,可以看到,通过 afterNodeAccess 方法把当前访问节点移动到了队尾,其实不仅仅是 get 方法,执行 getOrDefault、compute、computeIfAbsent、computeIfPresent、merge 方法时,也会这么做,通过不断的把经常访问的节点移动到队尾,那么靠近队头的节点,自然就是很少被访问的元素了。

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

--结束END--

本文标题: 源码解析带你了解LinkedHashMap

本文链接: https://lsjlt.com/news/135727.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 源码解析带你了解LinkedHashMap
    目录元素存储关系继承体系属性构造方法无参有参按插入顺序访问newNodelinkNodeLast链表节点的删除LRU(Least recently used,最近最少使用)栗子元素被...
    99+
    2024-04-02
  • Java源码解析之LinkedHashMap
    目录一、成员变量二、构造函数三、重要方法一、成员变量 先来看看存储元素的结构吧: static class Entry<K,V> extends HashMap.No...
    99+
    2024-04-02
  • 一篇带你解析入门LongAdder源码
    目录1、LongAdder由来2、LongAdder与AtomicLong的简单介绍3、AtomicLong3.1 AtomicLong实现原理3.2 AtomicLong瓶颈分析4...
    99+
    2024-04-02
  • Android AsyncTask完全解析 带你从源码的角度彻底理解
    我们都知道,Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制。之前我也写过了一篇文章从源码层面分析了Android...
    99+
    2022-06-06
    asynctask 源码 Android
  • 【LinkedHashMap】| 深度剥析Java SE 源码合集Ⅴ
    目录 1. 概述2. 类图3. 属性4. 构造方法5. 创建节点6. 节点操作回调6.1 afterNodeAccess6.2 afterNodeInsertion6.3 afterNodeRemoval 7. 转换成数组8. ...
    99+
    2023-08-18
    java 开发语言 数据结构
  • Android AsyncTask 完美解析 看不懂源码你就输了
    1.简介 android.os.AsyncTask,一个执行异步操作的类,我们可以使用它来处理后台任务,并且在UI线程中处理结果,而无需关心线程...
    99+
    2022-06-06
    asynctask 源码 Android
  • 通过代码实例带你了解Promise
    本篇文章通过多段代码实例带大家了解 Promise 的基础用法,以及更进一步掌握 Promise 异步存取的思想。之前一直有听说 Promise 的威名,但是总觉得是个较为深奥的东西,有点畏难而没能真正地去了解。最近看了李立超老师在B站传的...
    99+
    2023-05-14
    前端 JavaScript Node.js
  • 一文带你了解Go语言如何解析JSON
    目录JSON 解析为结构体JSON 解析为数组解析 JSON 嵌入对象自定义属性名称的映射非结构化数据的映射总结JSON 解析为结构体 JSON 的结构是 key-value,最直观...
    99+
    2023-01-12
    Go语言解析JSON Go 解析JSON Go语言 JSON
  • 带你深入了解Vue.$nextTick(原理浅析)
    白话一点就是说,其实这是和JS当中的事件循环是息息相关的,就是Vue不可能对每一个数据变化都做一次渲染,它会把这些变化先放在一个异步的队列当中,同时它还会对这个队列里面的操作进行去重,比如你修改了这个数据三次,它只会保留最后一次。这些变化是...
    99+
    2023-05-14
    $nextTick 前端 Vue.js
  • 九妹带你了解oracle
     一.oracle 体系架构  Oracle的体系结构是数据库的组成,工作过程,以及数据库中数据的组织与管理机制,要了解oracle数据库的体系结构,就必须要理解oracle的...
    99+
    2024-04-02
  • OldWang带你了解MySQL(二)
    文章目录 🔥创建与删除数据库🔥MySQL数据类型🔥创建表与删除表🔥修改表 🔥创建与删除数据库 创建数据库...
    99+
    2023-09-26
    mysql 数据库 java
  • 一文带你了解Java
    今天就跟大家聊聊有关一文带你了解Java,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java 简介Java是由Sun Microsystems公司(现已被oracle公司收购)于1...
    99+
    2023-05-31
    java ava
  • 手把手带你了解Python数据分析--matplotlib
    目录柱形图条形图折线图饼图和圆环图分离饼图块圆环图总结柱形图 bar()函数绘制柱形图 import matplotlib.pyplot as pl x = [1,2,3,4,5,6,7] y = [15,69,...
    99+
    2022-06-10
    Python Pythonmatplotlib
  • 带你了解C++的IO流
    目录一、C语言的输入与输出二、C++中流的概念三、C++IO流1.C++标准IO流2. C++文件IO流 四、stringstream总结一、C语言的输入与输出 C语言中我...
    99+
    2024-04-02
  • 带你了解HTTP黑科技
    这篇文章主要讲解了“带你了解HTTP黑科技”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“带你了解HTTP黑科技”吧!HTTP 内容协商什么是内容协商在 HT...
    99+
    2024-04-02
  • 【MySQL】一文带你了解SQL
    🎬 博客主页:博主链接 🎥 本文由 M malloc 原创,首发于 CSDN🙉 🎄 学习专栏推荐:LeetCode刷题集! ...
    99+
    2023-09-06
    mysql sql 数据库
  • SpringApplicationListener源码解析
    目录正文ApplicationListener介绍ApplicationListener使用定义事件:定义事件的监听者发布事件监听者收到发布的事件信息ApplicationListe...
    99+
    2023-01-15
    Spring ApplicationListener Spring 源码解析
  • Vue3 AST解析器-源码解析
    目录1、生成 AST 抽象语法树2、创建 AST 的根节点3、解析子节点4、解析模板元素 Element5、示例:模板元素解析上一篇文章Vue3 编译流程-源码解析中,我们从 pac...
    99+
    2024-04-02
  • Redis详解(一)冰叔带你了解Redis
    Redis 是一种基于 键值对 的 NoSQL 数据库。与很多键值对数据库不同,Redis 提供了丰富的 值数据存储结构,包括 string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)、bitmap(...
    99+
    2020-02-04
    Redis详解(一)冰叔带你了解Redis
  • 带你了解Spring AOP的使用详解
    目录springmvc.xmlBankDaoAdminCheckBankDaoImplLogInfoTransmactionAdminCheckInterceptorLogInfoI...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作