JDK1.8 HashMap.put()操作的源码解读与理解

HashMap jdk1.8 put get 操作步骤 put步骤总结如下: ①. 判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容,初始容量是16; ②. 根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如果table[i]不为空,转向③; ③. 判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转... 阅读详情
/**
     * Implements Map.put and related methods
     *
     * @param hash key的哈希值
     * @param key the key
     * @param value 待存入列表的值
     * @param onlyIfAbsent 如果为真,不会改变值
     * @param evict 如果为false,则表处于创建模式
     * @return 之前的value, or null if none
     */
//注意:单独占用一行或者多行的注释,则是对它下方的代码进行解释。
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i; //n用来存放数组的长度,i用来存放计算得的下标
        if ((tab = table) == null || (n = tab.length) == 0) //判断数组是否为空
            n = (tab = resize()).length; //初始化数组,长度默认时16
        /*
         n-1是为了获取的下标范围能够在数组长度之内。
		 因为数组的长度都是2的次方,当进行-1操作之后,低位都是1。在 &hash时得到的就是与都是1的低位			 长度相同的原hash二进制的值
		 取个例子,如何数组长度为16时
			十六的二进制:0001 0000
			 hash二进制:1011 0110
			 (16-1)&hash
		 	 0000 1111
		 	 1011 0110
		 	 根据&运算符的特性
		 	 结果就是 0110,0110的十进制就是数组下标。
		 			
        */
        if ((p = tab[i = (n - 1) & hash]) == null) 
            tab[i] = newNode(hash, key, value, null);//直接存放到数组中。
        else { //否则说明出现了hash冲突,也就是(n-1)&hash得到得下标对应得数组位置已经存放了结点。
            Node<K,V> e; K k;  //声明一个结点,以及与Key类型相同得变量,遍历结点时需要用到。
            /*
            在上一if中,p已经指向了tab[i = (n - 1) & hash]]的对象,也可以说是链表头。因为数组中
            每一个元素都是链表结构。
          	这里的判断有三个
          		1、p.hash == hash: 链表头Node的hash是否与要插入的hash相同。
          						        &
          						  (
          		2、((k = p.key) == key:链表头Node的key是否与要插入的key相同
          								||
          		3、(key != null && key.equals(k)): key不为空。并将key的内容不与Node的相同。
          							)
          		2和3是一个组合也就说,两个判断中只要有一个满足条件就可以。
            */
            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 {  //当上面的条件都不满足时,也就是出现key相同或者链表已经转变红黑树的情况,就对						链表进行遍历
                for (int binCount = 0; ; ++binCount) {
                    /*
                    如果当前结点为空,则将新的结点插入。
                    */
                    if ((e = p.next) == null) { 
                        p.next = newNode(hash, key, value, null);
                        /*
                        	判断链表的长度是否达到数化的阈值。当链表的长度等于 >= 8时树化
                        */
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash); //执行树化的方法。
                        break;
                    }
                    /*
                    与检查链表头Node的判断相同,都是判断否存入的是同一个key。相同的话就直接退出
                    */
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e; //获取下去结点的必备条件。 e = p.next; p = e;
                }
            }
            /*
            	这里判断为真说明 新插入的结点的key与之前插入的结点重复
            	这里的操作就是,将该新的Value更换结点上的value,返回旧的value值
            */
            if (e != null) { // existing mapping for key
                V oldValue = e.value; //获取结点上的value
                if (!onlyIfAbsent || oldValue == null) //判断是否可以更改值。
                    e.value = value; 
                afterNodeAccess(e); //回调。
                return oldValue;//返回久的值
            }
        }
        ++modCount;  //统计链表的修改次数
        if (++size > threshold) //如果当前数组中的总结点数大于扩容阈值。对数组进行扩容
            resize(); //扩容
        afterNodeInsertion(evict);//转移
        return null;
    }

个人的理解:

​ 上面的注释就是我对于JDK1.8的HashMap在进行Put的时候底层的实现原理,简单总结一下put的实现过程。

​ 1、 调用put 的时候,传入两个变量 key 和 value,put会调用putVal方法 传入key计算得出的hash值、value、对结点的操作类型onlyIfAbsent(是否可以改变值)、数组目前的状态evict(该表是目前是否处于创建状态)。

2、 进入putVal之后,由于HashMap的数组是使用懒加载机制创建的,所以会先判断当前的数组是否已经初始化,如果未初始化则先进行数组的初始化,长度默认是16。

3、 数组初始化完成之后,使用传入的hash计算出该结点在数组中的下标。

4、 得出下标后,定位到数组中该下标的元素,判断是否已经存入值,也就是是否发生过hash冲突,如果没有就直接将值存储该下标的数组元素中,成为链表的头节点。

5、 如果定位到该下标的元素发现已经存有值,先对头结点进行判断,判断目前存入的key是否与其的key相等,如果相等则将新value更换原有的value。并返回原先的value。否则继续向下遍历链表,遍历过程中如果发现有相等的key则进行前面所说的更新value操作。如果遍历完整个链表发现都没有出现key冲突,则将创建新结点插入链表的尾部。

6、 插入新结点后判断链表的长度是否大于8,如果大于8则将链表进行红黑树化操作。

7、 判断当前数组中总结点的个数是否达到扩容的阈值,满足条件则对数组进行扩容,创建新的数组,将原数组中结点存入新的数组中。

这个是我个人在研究HashMap 进行put操作时底层实现原理的理解,如果大家在浏览过程中,发现有理解错误的地方可以在评论中留言,后面我再进行更改。

Altium Designer20-柔性PCB绘制技巧 Altium Designer2020-柔性PCB绘制技巧 注:教程所用PCB随意找的,并没有完全绘制完,大家学习PCB折弯方法即可。 1.打开PCB,点击视图->板子规划模式1,如下图所示 2.点击设计->定义分割线,用两条分割线绘出要折弯的区域 3.点击设计->定义弯曲线(弯曲线呈现黄色) 4.用快捷键d,k进入layer manage stack(层叠管理器),在f... 阅读详情

相关推荐

水文模型新手必看:用SWAT-CUP做参数率定,如何正确设置预热期、率定期和验证期?(附数据准备避坑指南)

本文详细介绍了使用SWAT-CUP进行水文模型参数率定的完整流程,重点解析了预热期、率定期和验证期的正确设置方法,并提供了数据准备的避坑指南。通过实操步骤和常见问题解决方案,帮助新手快速掌握SWAT-CUP参数率定的核心技巧,提升水文模型模拟精度。

weixin_26875109的博客 373

HashMap源码解析《一》put方法

在jdk1.8里边 hashmap的实现原理不仅仅只由位桶+链表实现 ,增加位桶+红黑树实现,在桶中链表存储的元素个数到达阈值时(默认为8),将在底层将链表转为红黑树,但因为我本人红黑树掌握的并不好,所以不讨论有关红黑树,本文主要讲解基础,hashmap的put方法,其他请等待下文;一,所涉及到的名词;1,bucket   桶,对于系统开始初始化hashmap的时候,会创建一个长度为capacit...

Embra_ce的博客 619

CentOS 7 常用命令大全

CentOS中Linux命令

m0_63075763的博客 2018

JDK1.8-HashMap-Put操作源码流程解析

1.Put 操作流程图 2.当put操作发生hash冲突的时候,会用拉链法解决冲突。但是如果在同一内存地址冲突的数据超过8个时,并且这个时候Node数组的容量大于等于64,那么这个时候再在该位置添加元素会把单链表变成双向链表最后再转换成红黑树来进行存储数据。采用红黑树存储数据目的是在该冲突的地址查询数据的时候能够更快,提高查询效率。存储结构转换图: 3.红黑树为了保证其特定,在插入元...

u012874209的博客 904

基于STM32的RS485土壤氮磷钾与PH传感器数据采集与OLED显示实战(附完整代码)

本文详细介绍了基于STM32单片机通过RS485协议采集土壤氮磷钾与PH传感器数据的实战项目。涵盖硬件选型、连接方法、Modbus-RTU通信协议解析、STM32程序实现及OLED显示,提供完整代码和调试技巧,适用于农业物联网环境监测系统。

kotlin6android的博客 335

R语言机器学习算法实战系列(四)随机森林算法分类器+SHAP值 (Random Forest)

本文介绍了如何使用R语言实现随机森林算法,用于构建乳腺癌分类器。随机森林通过多棵决策树投票判断标签,具有避免偏差和提升模型效果的优势。文章详细讲解了数据下载、R包加载、数据预处理、特征选择、模型构建与评估等步骤。数据集包含569份恶性和良性肿瘤样本的32类指标,通过随机森林模型进行特征选择和分类。最终,文章提供了完整的代码和可视化结果,帮助读者理解并实现随机森林算法。

专注生信领域 3319

Jdk1.8 HashMap中put()方法源码分析

1.说明下环境,为jdk1.8,仅对put方法进行源码分析。 2.特别说明:我使用的是这个构造器: //15表示自定义map的初始容量为15 //0.7f表示自定义负载因子为0.7 HashMap<String, String> mapMine = new HashMap<String, String>(15,0.7f); 并不是下面的构造器: HashMap<String, String> mapMine = new HashMap<String, Strin

前路无畏的博客 1万+

实时数字人SoulX-FlashHead 音视频不对齐解决

【代码】实时数字人SoulX-FlashHead 音视频不对齐解决。

jacke121的专栏 200

JDK1.8HashMap源码解析之put操作

嗯,这是一篇想了很久之后准备写的一篇关于HashMap源码解析的文章,如有不足之处欢迎下方评论! 一、变量 /** * 默认容量 */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; /** * 最大容量 */ static final int MAXIMUM_CAPACITY = 1 << 30; /** * 加载因子 */

weixin_43608392的博客 526

WOFOST作物模型(7):6.0.6版本的PCSE使用(多层水分平衡和SNOMIN碳氮模型的集成)

wofost81文件结构如上,其中所需的参数可从github上获取然后input下有两个需要调用的功能函数py文件,需要拖到自己的运行py文件同级目录下在使用土壤模块SNOMIN进行作物生长模型模拟时,需要为土壤剖面的不同层次提供多种输入变量。这些变量通常不随年份变化,因此会统一在土壤文件中定义。本节将说明如何将这些输入变量整合到一个字典中,进而生成SNOMIN能够读取的土壤文件。

所有专家都曾始于新手 637

UE5 GAS 学习笔记 1.2游戏标签

这一节对GameplayTag游戏标签进行详细的讲解。

CloudHuCoding 1927

面试必问的HashMap源码put()方法和resize()方法——基于JDK1.8

目录一、前言二、 HashMap 的构造方法三、 put()方法(一)、源码注释(二)、流程图四、 resize()方法(一)、源码注释(二)、流程图(三)、 resize方法的注意事项 一、前言 HashMap太太太常用了,不做过多的介绍。进入正文直接冲源码。 本文主要是基于1.8的HashMap讲述部分源码,主要重点是put()方法和resize()方法 二、 HashMap 的构造方法 /** * 设置初始化容量,调用的是下面的重载方法 */ public HashMap(int initialCap

爱读史的小马的博客 2570

【时时三省】tessy 进入调试模式 教程

山不在高,有仙则名。水不在深,有龙则灵。----优快云 时时三省。

时时三省的博客 771

HashMap源码解读(中篇)

HashMap的属性以及Put方法逐句解析

VIBE的博客 2281

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

JDK8 HashMap源码行级解析 史上最全最详细解析

源码面前,了无秘密。 除了红黑树部分,本文对HashMap的1789行源码进行了详细解析。 本文将会在代码里把注释写得尽可能地全,以理解源码的各个细节,而在源码片段后则将进行提纲挈领的总结性讲解。本文既适合已经阅读过部分源码的同学,可以来这里查漏补缺,或解决疑惑;也适合从头开始阅读HashMap源码的同学。

anlian523的博客 2931

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

JDK1.8源码解析-HashMap(一)

JDK1.8源码解析-HashMap I 本文主要介绍了JDK1.8中HashMap的实现原理,对部分常用的API进行源码解读,网上该主题的资源非常多,作者参考了很多相关文章不在文中一一列举了,在此基础上加入了自己对部分源码的理解。 1. HashMap概述 根据JDK1.8中HashMap的JavaDo的描述,HashMap可以允许key为null,value为null的键值对,值...

Java By-talk 2333

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

HashMap源码put()方法逐行详解原理(JDK1.8)

HashMap是java中常用的一个集合, 也是面试大公司几乎必问的一个知识点. 无论是为了面试还是提升能力, 或是学习源码的编程思想, 了解它的底层原理是很重要的. 要了解HashMap的底层原理, 就得深入理解它的源码. 本文将逐行逐行解释HashMap的put()方法及其涉及到的原理和思想, 希望对大家有帮助. 本次我们讨论的是JDK1.8的HashMap. 如果哪里说得有错误或是不足, 欢...

weixin_40828249的博客 810

HashMap底层原理及jdk1.8源码解读【吐血整理1.3w字长文】

文章目录一、前言二、存储结构介绍三、源码分析之常用变量解读四、源码分析之构造方法解读五、源码分析之常用方法解读1、tableSizeFor方法解读2、hash方法解读3、put方法解读4、resize方法解读5、get和containsKey方法解读6、remove方法解读六、总结 一、前言 写在前面:小编码字收集资料花了一天的时间整理出来,对你有帮助一键三连走一波哈,谢谢啦!! HashMap在我们日常开发中可谓经常遇到,HashMap 源码和底层原理在现在面试中是必问的。所以我们要掌握一下,也是作为两年

小王博客基地 1384

HashMap学习篇put()与resize()的扩容机制(JDk1.8)

HashMap学习篇resize()的扩容机制(JDk1.8) 先提一下HashMap的底层数据结构为数组+链表+红黑树。 1.数据初始化 //将之前的数组的数据保存出来 Node<K,V>[] oldTab = table; //获取之前保存数据的长度,防止未初始化报错 int oldCap = (oldTab == null) ? 0 : oldTab.length; //获取之前扩容临界值(capacity*l

Violet 638

JDK1.8的HashMap源码解读(一)

JDK1.8种的HashMap底层由1.7的数组+链表实现改为了由数组+链表+红黑树来实现,这里只是解读出红黑树以外的常用方法代码的思路。 直接一边看源码,一边加注释,这样过一遍,要好一些。 一、变量解读 /** * 初始默认容量——16。 * 这里用了移位操作 */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // a...

反反复复的博客 276

手撕 JDK1.8 HashMap源码

手撕 JDK1.8 HashMap源码1.HashMap核心属性2.构造方法3.HashMap put 方法分析 => putVal方法分析4.HashMap resize 扩容方法分析(核心)5.HashMap get 方法分析6.HashMap remove 方法分析7.HashMap replace 方法分析8.视频讲解 什么是哈希:把任意长度的输入,通过Hash算法变成固定长度的输出。 看源码之前也可以先看看hashMap原理 前言: 由于HashMap源码涉及了红黑树的操作,但是这里我没有对

冲冲冲的博客 385

HashMap1.8源码解读之新增/修改——put()

一.引读     这篇意在分析HashMap1.8源码的put()方法。对于基础数据结构的操作,无非就是增删改查,而这篇我们要阐述的就是JDK1.8里HashMap里的新增/修改,也就是put()方法。     对于对HashMap还不熟悉的读者,建议先看下我之前写的拙作:     1.HashMap源码解读之原理浅析—前传篇     2.HashM

qq_42307562的博客 547

新所得库 - Java集合 - HashMap & TreeMap源码解读实战篇

HashMap为什么需要链表+红黑树混合?红黑树的转换阈值是多少?为什么设定为8?TreeMap添加元素是否需要实现 hashCode/equals?(不需要)HashMap的键为什么不需要实现 Comparable?TreeMap和HashMap谁更快?(大多数场景HashMap更快)│ 计算 hash值 │↓│ 计算桶索引 i │↓│ tab[i] 为空?│是 否↓ ↓创建新节点 哈希冲突判断├ 链表插入└ 红黑树插入put() 的底层流程是怎样的?为什么要使用高位扰动?

tang7mj的博客 1455

hashmap是单向链表吗_面试必备:HashMap(JDK1.8)原理以及源码分析

对于HashMap想必大家都不陌生,无论是平时code还是面试都经常和它打交道。今天我们通过源码的层面来分析一下它的实现原理,注意本文基于的是JDK1.8。问题是从哪边开始聊起呢?我觉得不妨先从一段熟悉的代码开始。MapString> map = map.put(1, "Jack");然后我们会迫不及待点开HashMap这个类,发现里面有大量的属性和方法,一脸懵逼。那就直接点开pu...

weixin_31261145的博客 2938

hashmap中put和putVal方法

文章目录前言一、HashMap的重要属性二、put和putVal方法三、数组下标的计算方式总结前言我想只要JAVA程序员,都躲不过HashMap这一关,面试官的HashMap夺命连环问经常把求职者虐的体无完肤。因此,本篇文章以JDK8为例,对HashMap的底层源码做一个解析,帮助大家更好的理解HashMap的底层原理。一、HashMap的重要属性我想大家都应该知道在JDK8中HashMap的数据结构是数组+链表+红黑树。

gcfffff的博客 1037

深入理解HashMap扩容(JDK1.8)---源码分析

HashMap有自动扩容机制,那么它是如何扩容的?本篇带你跟着源码一步步走近。以下都是基于jdk1.8的。 Let's start 从HashMap的put方法入手,逐步深入: /** * Associates the specified value with the specified key in this map. * If the map previously co...

天涯~的博客 1332
上一篇: 震惊! Docker启动tomcat访问竟然报404?看看这位小伙子如何处理!
下一篇: 安装多个版本JDK,使用IDEA自由切换。
小码林marlin
博客等级 码龄9年 30粉丝 29原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值