LinkedHashMap 集合源码分析

LinkedHashMap 集合源码分析

文章目录

  • LinkedHashMap 集合源码分析
  • 一、字段分析
  • 二、内部类分析
  • 三、构造方法分析
  • 四、内部方法分析
  • 五、总结


在这里插入图片描述

  • LinkedHashMap 是 HashMap 的子类,在 HashMap 的基础上维护了双向链表,保证了有序性。默认是不排序的,可在初始化时传入 accessOrder = true,则进行排序

一、字段分析

// 指向LinkedHashMap 维护的双向链表的头结点
transient LinkedHashMap.Entry<K,V> head;
// 指向LinkedHashMap 维护的双向链表的尾结点
transient LinkedHashMap.Entry<K,V> tail;
// 是否排序:默认false:不排序。设为true时:越近访问的节点越靠近尾结点,即头结点 -> 尾结点
// 按 最近访问时间降序排列,即越靠近尾结点,离上次访问时间越近。
final boolean accessOrder;

二、内部类分析

//可以看到是继承了 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);}}

三、构造方法分析

	//传入默认的初始容量 和 加载因子,默认不排序public LinkedHashMap(int initialCapacity, float loadFactor) {super(initialCapacity, loadFactor);accessOrder = false;}//闯入默认的初始容量,默认不排序public LinkedHashMap(int initialCapacity) {super(initialCapacity);accessOrder = false;}//无参构造,默认不排序public LinkedHashMap() {super();accessOrder = false;}//传入集合m来,使用集合m的所有元素来构建 LinkedHashMap,默认不排序public LinkedHashMap(Map<? extends K, ? extends V> m) {super();accessOrder = false;putMapEntries(m, false);}//传入初始容量,加载因子,也可指定进行排序即truepublic LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder) {super(initialCapacity, loadFactor);this.accessOrder = accessOrder;}

四、内部方法分析

  • LinkedHashMap 的添加元素、删除元素,扩容等方法都是直接使用 了 HashMap 的方法。
  • 但在 HashMap 的基础上做了扩展,体现了多态性。主要是三种方法:
    • afterNodeRemoval:将被删除的节点从 LinkedHashMap 维护的双向链表中移除。
    • afterNodeInsertion:用来判断是否删除 LinkedHashMap 维护的双向链表的头结点,即最久未被访问的节点。
    • afterNodeAccess:将传入的node节点放置末尾,即最近访问的元素。
    //将 e 节点从双向链表中删除void afterNodeRemoval(Node<K,V> e) { // unlinkLinkedHashMap.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;elseb.after = a;if (a == null)tail = b;elsea.before = b;}//evict:true:删除最久未被访问的元素,即双向链表的头结点void afterNodeInsertion(boolean evict) { // possibly remove eldestLinkedHashMap.Entry<K,V> first;if (evict && (first = head) != null && removeEldestEntry(first)) {K key = first.key;removeNode(hash(key), key, null, false, true);}}//节点e是刚刚访问的节点,判断是否需将其移动至双向链表的尾结点void afterNodeAccess(Node<K,V> e) { // move node to lastLinkedHashMap.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;elseb.after = a;if (a != null)a.before = b;elselast = b;if (last == null)head = p;else {p.before = last;last.after = p;}tail = p;++modCount;}}

五、总结

  • 我们知道 HashMap 并不能保证有序性,而 LinkedHashMap 作为 HashMap 子类解决了排序的问题。在构造时,通过传入afterNodeAccess = true 来设置LinkedHashMap是有序的。
  • 通过维护双向来链表来保证有序性,拥有变量 head 和 tail 分别指向双向链表的头结点和尾结点,越靠近 尾结点,越是最近访问的节点,越是靠近头结点,越是越久未被访问的节点。
  • 可用于实现 LRU 算法:
    • 使用 LinkedHashMap 实现 LRU:

      class LRUCache extends LinkedHashMap<Integer, Integer>{private int capacity;public LRUCache(int capacity) {super(capacity, 0.75F, true);this.capacity = capacity;}public int get(int key) {return super.getOrDefault(key, -1);}public void put(int key, int value) {super.put(key, value);}@Overrideprotected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {return size() > capacity; }
      }
      
    • 不适用 LinkedHashMap 实现 LRU:

      class LRUCache {static class Node{public int key;public int val;public Node prev;public Node next;public Node(){this.key = -1;this.val = -1;}public Node(int key,int val){this.key = key;this.val = val;}}//最大容量    int capacity;//节点数量int size;//虚拟头节点Node dummyHead;//虚拟尾节点Node dummyTail;Map<Integer,Node> map = new HashMap<>();public LRUCache(int capacity) {this.capacity = capacity;this.size = 0;dummyHead = new Node();dummyTail = new Node();dummyHead.next = dummyTail;dummyTail.prev = dummyHead;}public int get(int key) {if(!map.containsKey(key)){return -1;}Node node = map.get(key);//将该节点从原位置删除remove(node);//将该节点添加到链表尾部addLeast(node);return node.val;}public void put(int key, int value) {Node cur = new Node(key,value);remove(map.get(key));addLeast(cur);}//删除节点public void remove(Node node){if(node == null) return;node.prev.next = node.next;node.next.prev = node.prev;node.next = null;node.prev = null;size --;map.remove(node.key);}//将节点添加到尾部public void addLeast(Node node){Node prev = dummyTail.prev;prev.next = node;node.prev = prev;node.next = dummyTail;dummyTail.prev = node;size ++;map.put(node.key,node);//超过最大容量了if(size > capacity){removeFirst();}}//删除头节点public Node removeFirst(){if(dummyHead.next == dummyTail) return null;Node remove = dummyHead.next;remove(remove);return remove;}
      }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/801208.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript模块化开发的前世今生

一个兜兜转转&#xff0c;从“北深”回到三线城市的小码农&#xff0c;热爱生活&#xff0c;热爱技术&#xff0c;在这里和大家分享一个技术人员的点点滴滴。欢迎大家关注我的微信公众号&#xff1a;果冻想 前言 现代化的编程语言&#xff0c;基本都支持模块化的开发&#xff…

Transformer算法详解

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章&#xff1a;TensorFlow入门实战&#xff5c;第3周&#xff1a;天气识别&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 一、文本输入人类理解 词向量&#xff08;E…

ICLR24_OUT-OF-DISTRIBUTION DETECTION WITH NEGATIVE PROMPTS

摘要 分布外检测&#xff08;OOD Detection&#xff09;的研究对于开放世界&#xff08;open-world&#xff09;学习非常重要。受大模型&#xff08;CLIP&#xff09;启发&#xff0c;部分工作匹配图像特征和提示来实现文本-图像特征之间的相似性。 现有工作难以处理具有与已…

Java常用API_System——常用方法及代码演示

1.System.exit(int status) 方法的形参int status为状态码&#xff0c;如果是0&#xff0c;说明虚拟机正常停止&#xff0c;如果非0&#xff0c;说明虚拟机非正常停止。需要将程序结束时可以调用这个方法 代码演示&#xff1a; public class Test {public static void main(S…

UVA156 反片语 解题报告

UVA156 反片语 解题报告 题目链接 https://vjudge.net/problem/UVA-156 题目大意 输入一些单词&#xff0c;找出所有满足如下条件的单词&#xff1a;该单词不能通过字母重排&#xff0c;得到输入文本中的另外一个单词。在判断是否满足条件时&#xff0c;字母不分大小写&…

浏览器禁用cookie后session还能用吗?

1.背景 最近有朋友问我其面试时遇到的一个不常见的问题&#xff1a;浏览器禁用cookie后session还能用吗&#xff1f;&#xff0c;怎么解答。 2.cookie与session联系入手 2.1 理论基础 一般默认情况下&#xff0c;在会话中&#xff0c;服务器存储 session 的 sessionid &…

第四百四十七回

文章目录 1. 概念介绍2. 思路与方法2.1 实现思路2.2 使用方法 3. 内容总结 我们在上一章回中介绍了"如何在页面上显示蒙板层"相关的内容&#xff0c;本章回中将介绍overlay_tooltip这个三方包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本…

AGI(通用人工智能Artificial General Intelligence)知识点

通用人工智能AGI知识点 AGI1. prompt提示工程是什么&#xff1f;2. 怎么构建prompt&#xff1f;3. Function Calling是什么&#xff1f;4. RAG是什么&#xff1f;构建 RAG 模型的步骤&#xff1a;RAG 的优势和应用场景&#xff1a; 5. 离线和在线的RAG怎么构建&#xff1f;5. 构…

【SCI绘图】【热力图系列2 R】多特征相关性分析热力图指定聚类 R

SCI&#xff0c;CCF&#xff0c;EI及核心期刊绘图宝典&#xff0c;爆款持续更新&#xff0c;助力科研&#xff01; 本期分享&#xff1a; 【SCI绘图】【热力图系列2 R】多特征相关性分析热力图指定聚类 R 1.环境准备 library(gplots) library(RColorBrewer)2.数据读取 ###…

VUE实现增删改查功能

Vue 中实现增删改查功能 增删改查&#xff08;CRUD&#xff09;是 Web 应用程序中的基本操作&#xff0c;它可以让我们在数据库中创建、读取、更新和删除数据。在 Vue.js 中实现 CRUD 功能相对简单。 创建 创建新记录时&#xff0c;我们将使用 v-model 双向绑定数据并向服务…

python小项目——时钟模拟

钟表是一种计时的装置&#xff0c;也是计量和指示时间的精密仪器。钟表的样式千变万化&#xff0c;但是用来显示时间的表盘相差无几&#xff0c;大多数钟表表盘的样式由刻度&#xff08;共60个&#xff0c;围成圆形&#xff09;、指针&#xff08;时针、分针和秒针&#xff09;…

SpringBoot中这样用ObjectMapper,才够优雅!

目录 背景步骤在SpringBoot项目中要实现对象与Json字符串的互转&#xff0c;每次都需要像如下一样new 一个ObjectMapper对象&#xff1a;这样的代码到处可见&#xff0c;有问题吗&#xff1f;我们要使用jmh测试几种方式的区别&#xff1a;所以在我们真正使用的时候不要在方法中…

JavaScript 书写位置

JS 分为三种使用方法&#xff0c;分别为行内&#xff0c;内嵌&#xff0c;外部。 行内式&#xff08;不推荐使用&#xff09; 行内就是 将 JS 代码直接写在 HTML 标签上 &#xff0c;这种方式的结构、行为分离不够彻底&#xff0c;不利于后 期维护&#xff0c;复用性不强…

2024年3月30日~2024年4月7日周报

文章目录 一、前言二、创意收集2.1 多任务学习2.1.1 多任务学习的定义与优势2.1.2 多任务学习的分类 2.2 边缘检测2.2.1 基础理论2.2.2 sobel代码介绍2.2.3 canny代码介绍 三、《地震速度模型超分辨率的多任务学习》3.1 M-RUDSR架构3.2 详细介绍3.3 实验设置 四、实验五、小结5…

揭秘程序员面试技巧,助你轻松拿offer!

上文 程序员面试是求职者展现自身技术实力、沟通能力和职业素养的关键环节。为了在面试中脱颖而出&#xff0c;求职者需要掌握一些实用的面试技巧。以下将详细阐述程序员面试技巧&#xff0c;助您在面试中取得更好的成绩。 一、面试前准备 了解公司及职位 在面试前&#xff0…

操作系统与编程系列专栏(一):导言

在一间充满了键盘敲击声和低语讨论的办公室内&#xff0c;两位资深程序员&#xff0c;老马和老王&#xff0c;围绕着一个永恒的话题展开了讨论。他们的对话不仅引发了思考&#xff0c;也为那些在软件开发道路上前行的人提供了不少启示。 老马&#xff1a;“我觉得深入了解操作系…

【leetcode面试经典150题】18.整数转罗马数字(C++)

【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主&#xff0c;题解使用C语言。&#xff08;若有使用其他语言的同学也可了解题解思路&#xff0c;本质上语法内容一致&…

【LeetCode题解】2009. 使数组连续的最少操作数

文章目录 [2009. 使数组连续的最少操作数](https://leetcode.cn/problems/minimum-number-of-operations-to-make-array-continuous/)思路&#xff1a;一、排序去重滑动窗口代码&#xff1a; 2009. 使数组连续的最少操作数 思路&#xff1a;一、排序去重滑动窗口 1.对数组进行…

C语言代码块及块级作用域

代码块 所谓代码块&#xff0c;就是由{ }包围起来的代码。代码块在C语言中随处可见&#xff0c;例如函数体、选择结构、循环结构等。不包含代码块的C语言程序根本不能运行&#xff0c;即使最简单的C语言程序也要包含代码块。C语言允许在代码块内部定义变量&#xff0c;这样的变…

P8794 [蓝桥杯 2022 国 A] 环境治理

P8794 [蓝桥杯 2022 国 A] 环境治理 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include <iostream> using namespace std; #define ll long long const int N150; const int inf0x7fffffff; int n,q; int d[N][N],l[N][N]; int t[N][N]; void floyd() {for(int k0…