LinkedHashMap源码分析

类结构图

在这里插入图片描述

从类图结构可以看出,LinkedHashMap继承自HashMap,里面很多实现都是HashMap的,这篇文章主要写出LinkedHashMap自实现的那部分

Entry

LinkedHashMap的每个元素项都是一个Entry类对象,该类继承自HashMap.Node类

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

数据结构图

最终LinkedHashMap的存储结构,包含有数组、单链表(维持HashMap中的key冲突情况)、双链表(LinkedHashMap的主结构)、红黑树(维持HashMap中的key冲突情况),具体如下图:
在这里插入图片描述

上图中的tail在实际中可能出现在两种位置,第1种位置是指向table桶内的值,并且该entry没有hash冲突;第2种是在有hash冲突下的指向,两者只会存在其中一种

put

LinkedHashMap的put实现完全继承HashMap的逻辑,作为子类,在newNode和afterNodeInsertion两个方法上做了重写,所以我们重点关注这2个方法

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null); //LinkedHashMap对newNode方法重写了
    else {
        Node<K,V> e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);  //LinkedHashMap实现了afterNodeInsertion
    return null;
}

创建LinkedHashMap的节点

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;  //原尾节点为空,就是链表为空,当前节点就是头节点head了
    else { //原链表不为空,设置当前节点的before节点为原尾节点tail,原尾节点的after为当前节点p,实现双向入链
        p.before = last;
        last.after = p;
    }
}

节点插入后的操作afterNodeInsertion钩子方法

void afterNodeInsertion(boolean evict) { // possibly remove eldest
    LinkedHashMap.Entry<K,V> first;
    //由于removeEldestEntry方法固定返回false,所以这个if永远进不去
    if (evict && (first = head) != null && removeEldestEntry(first)) {
        //其时这个方法内部,意思就是尾部插入一个新node,然后移除一个老的头部的node,这点有没有感觉像是LRU算法实现的逻辑
        K key = first.key;
        removeNode(hash(key), key, null, false, true);
    }
}

 protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
     return false;
 }

get

public V get(Object key) {
    Node<K,V> e;
    if ((e = getNode(hash(key), key)) == null)
        return null;
    if (accessOrder) // accessOrder默认是false,可以在构造方法中设置为true
        afterNodeAccess(e);  //把节点移到最后,其实还是LRU算法实现的逻辑,把最新访问的放到链表尾部
    return e.value;
}

void afterNodeAccess(Node<K,V> e) { // 把节点移动最后
    LinkedHashMap.Entry<K,V> last;
    if (accessOrder && (last = tail) != e) {
        /*
        当前节点p,p的前置节点b,p的后继节点a,关系如下:
        b<->p<->a
        */
        LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
        //当前节点要被扔到最后,所以after为null
        p.after = null;
        //b为null,表示当前p就是head节点,直接到a置为head就行
        if (b == null)
            head = a;
        else
            b.after = a; //p不是head,那么b的after就要变成a了
        if (a != null) 
            a.before = b; //a的before也要改成b了
        else
            last = b; // a也是null,那最后一个节点就b自己了
        if (last == null)  //到这证明,从头到尾只有p一个节点,那只能自己变成head
            head = p;
        else {
            p.before = last; //把p丢到尾部
            last.after = p;
        }
        tail = p;
        ++modCount; //修改次数加1
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【missing-semester】The shell

文章目录 shell 是什么shell 怎么用执行基本程序 Shell中的路径重定向输入输出管道piperoot用户的使用课后练习参考资料 我的操作环境&#xff1a;Windows11下的WSL2(Ubuntu20.04)&#xff0c;之后的所有操作都是基于这个前提的 shell 是什么 命令行操作语言&#xff0c;文本界…

pycharm安装库失败

项目场景 pycharm安装第三方库 问题描述 python 安装第三方库总是安装失败 原因分析&#xff1a; 提示&#xff1a;这里填写问题的分析&#xff1a; 1.网络 2.网墙 解决方案&#xff1a; 加个镜像 –trusted-host mirrors.aliyun.com

【EI会议征稿】第四届信息化经济发展与管理国际学术会议(IEDM 2024)

第四届信息化经济发展与管理国际学术会议&#xff08;IEDM 2024&#xff09; 2024 4th International Conference on Informatization Economic Development and Management 第四届信息化经济发展与管理国际学术会议&#xff08;IEDM 2024&#xff09;将于2024年2月23-25日在…

C++ opencv基本用法【学习笔记(九)】

这篇博客为修改过后的转载&#xff0c;因为没有转载链接&#xff0c;所以选了原创 文章目录 一、vs code 结合Cmake debug1.1 配置tasks.json1.2 配置launch.json 二、图片、视频、摄像头读取显示2.1 读取图片并显示2.2 读取视频文件并显示2.3 读取摄像头并写入文件 三、图片基…

现货黄金职业交易员怎么使用技术分析?

职业的交易员每天要处理很多不同的信息&#xff0c;其中只一部分是涉及技术指标。在这一部分处理技术分析的时间里&#xff0c;只能再分出少之又少的时间给技术指标。那职业交易员会利用做技术指标做什么呢&#xff1f;下面我们就来讨论一下。 识别行情。技术指标的主要作用就是…

TikTok女性创作者:媒体世界的新领袖

在数字时代&#xff0c;社交媒体已成为媒体和娱乐产业的关键组成部分&#xff0c;而TikTok作为最受欢迎的短视频分享平台之一&#xff0c;为女性创作者提供了一个独特的机会来在媒体世界中崭露头角。 这个平台不仅为女性创作者提供了一个创作和分享自己的声音、观点和创意的空…

(三)什么是Vite——Vite 主体流程(运行npm run dev后发生了什么?)

什么是vite系列目录: &#xff08;一&#xff09;什么是Vite——vite介绍与使用-CSDN博客 &#xff08;二&#xff09;什么是Vite——Vite 和 Webpack 区别&#xff08;冷启动&#xff09;-CSDN博客 &#xff08;三&#xff09;什么是Vite——Vite 主体流程(运行npm run dev…

江西产业链现代化1269行动计划引领新能源建设与职业教育教学改革的深度融合

江西产业链现代化1269行动计划引领新能源建设与职业教育教学改革的深度融合 在全球能源转型的时代背景下&#xff0c;江西省积极应对挑战&#xff0c;提出了产业链现代化1269行动计划。这一计划不仅着眼于推动新能源建设&#xff0c;还将新能源建设与职业教育教学改革紧密结合…

Axure9 基本操作(二)

1. 文本框、文本域 文本框&#xff1a;快速实现提示文字与不同类型文字显示的效果。 2. 下拉列表、列表框 下拉列表&#xff1a;快速实现下拉框及默认显示项的效果。 3. 复选框、单选按钮 4.

零成本体验美国云服务器,更方便的体验和选择

在当今数字化时代&#xff0c;云计算已经成为了企业和个人的首选。而美国云服务器免费试用&#xff0c;则为广大用户提供了一个零风险尝试的机会。作为一种高效、灵活、稳定的解决方案&#xff0c;美国云服务器可以为您的业务保驾护航。 什么是美国云服务器&#xff1f; 美国云…

掌握AI图像篡改检测工具,轻松识别图片造假

文章目录 一、前言1.1 背景与危害1.2会议探讨1.3 技术先行 二、亮点技术1&#xff1a;AI图像篡改检测技术2.1 传统方法Python实现步骤2.2 合合信息——PS纂改检测体验 三、亮点技术2&#xff1a;生成式图像鉴别3.1 生成式图像安全问题3.2 传统方法Python实现步骤3.2 合合信息—…

《Linux从练气到飞升》No.27 Linux中的线程互斥

&#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&#xff0c;你的&#x1f44d;点赞&#x1f64c;收藏❤️关注对我真的…

小DEMO:在vue中自定义range组件

1、组件样式 2、使用 import cSlider from /components/c-slider/c-slider.vue<div class"range"><cSlider v-model"cScale" change"cScaleChange" :min"1" :max"10"/> </div> 3、组件代码 <templa…

5+单基因+免疫浸润,这篇肿瘤预后文章你值得拥有

今天给同学们分享一篇生信文章“Systematic analysis of the role of SLC52A2 in multiple human cancers”&#xff0c;这篇文章发表在Cancer Cell Int期刊上&#xff0c;影响因子为5.8。 结果解读&#xff1a; 多种人类癌症中SLC52A2的mRNA表达 首先&#xff0c;作者使用GT…

virtualbox基本配置

全屏模式调出热键 右边的 ctrl home 键 安装增强功能 注意&#xff1a;virtualbox 自带那个安装增强功能点击后是没有效果的 1、启动虚拟机 2、设备 3、分配虚拟光驱 4、选择虚拟盘 5、选择对应iso文件&#xff0c;文件下载路径 6、双击对应文件安装&#xff0c;默认配置…

多区域OSPF配置

配置命令步骤&#xff1a; 1.使用router ospf 进程ID编号 启用OSPF路由 2.使用network 直连网络地址 反掩码 area 区域号 将其归于对应区域 注意&#xff1a; 1.进程ID编号可任意&#xff08;1-65535&#xff09; 2.反掩码用4个255相减得到 3.area 0 为主干区域 4.连接不…

虚拟机第一次如何打开

1、将别人的虚拟机拷贝到自己的电脑盘里&#xff1b; 2、打开VMware&#xff0c;选择“打开虚拟机”&#xff1b; 3、选择拷贝的虚拟机里的.vmx文件&#xff1b; 4、选择“播放虚拟机”&#xff1b; 5、如果出现一个选择框&#xff0c;选“我已复制改虚拟机”即可。

Python 中的 tqdm() 方法

tqdm&#xff08;阿拉伯语"taqaddum"的缩写&#xff0c;意为"进展"&#xff09;是Python中一个用于在循环中显示进度条的库。它提供了一种简单而又灵活的方式来监测代码执行的进度&#xff0c;特别是在处理大量数据或耗时较长的任务时非常有用。 1、安装 …

golang 解析oracle 数据文件头

package mainimport ("encoding/binary""fmt""io""os" ) // Powered by 黄林杰 15658655447 // Usered for parser oracle datafile header block 1 .... // oracle 数据文件头块解析 // KCBlockStruct represents the structure of t…

什么是美颜SDK?美颜SDK对比评测

美颜SDK在视频直播中发挥着越来越重要的作用。为了实现实时、高质量的美颜效果&#xff0c;各种视频直播美颜SDK应运而生。本文将对这些技术进行深入解析与比较。 一、技术原理解析 深度学习技术通过大量的训练数据学习人脸特征&#xff0c;从而实现更为自然的美颜效果。传统…