HashMap源码解析《一》put方法

HashMap之put详解(一) 文章目录1. 导读2. HashMap::put源码解析3. 红黑树的插入4. 链表转红黑树 1. 导读 这次的分享是关于HashMap::put, 主要是围绕下面几个方面展开: .1 HashMap::put源码解析; .2 红黑树插入的处理; .3 红黑树与链表的互转; 2. HashMap::put源码解析 因为HashMap::put的源码较长, 用下面的流程图来替代: 下面我们一步步来... 阅读详情

在jdk1.8里边 hashmap的实现原理不仅仅只由位桶+链表实现 ,增加位桶+红黑树实现,在桶中链表存储的元素个数到达阈值时(默认为8),将在底层将链表转为红黑树,但因为我本人红黑树掌握的并不好,所以不讨论有关红黑树,本文主要讲解基础,hashmap的put方法,其他请等待下文;

一,所涉及到的名词;

1,bucket   桶,对于系统开始初始化hashmap的时候,会创建一个长度为capacity的数组,数组里边存储元素的位置被称为桶,存储一个Node<K,V>

2,capacity    容量  capacity就是指HashMap中桶的数量,默认初始值为16,必须为2的幂

3,size  表示HashMap中存在KV的数量(数组和链表的总和),如果size到达threshold极限值会进行扩充。

4,LoadFactor 负载因子(装载因子) ,装载因子用来平衡HashMap满的程度,默认值为0.75f.计算HashMap的实时装载因子的方法为:size/capacity,而不是用已占用桶的数量去初以capacity  满的程度就是当前的桶中被占用了多少。  例如 现在capacity=16,占用了一个桶size = 1, 1/16 = 0.0625     就是表示现在有多满。

5,threshold   极限值    size的值到达极限值之后就会进行扩充。

threshold=capacity*loadFactor         例如现在capacity=16, loadFactor = 0.75   16*0.75 = 12  意思就是当现在桶和链表中的bin总量等于12 时,就会扩充

二,源码分析:

1.初始化:

HashMap 继承于AbstractMap,实现了Map,Cloneable,Serializable接口

Hashmap是无序的,有序的有TreeMap,LinkedHashMap等

 

静态成员定义:

static final int DEFAULT_INITIAL_CAPACITY = 1<<4;    //初始值为16,并且必须是2的幂

static final int MAXIMUM_CAPACITY = 1<<30;            //最大容量 2^30

static final float DEFALT_LOAD_FACTOR = 0.75f;       //负载因子

static final int TREEIFY_THRESHOLD = 8;             //由链表转为数的极限值

static final int UNTREEIFY_THRESHOLD = 6;          //由树转为链表的阈值

static final int MIN_TREEIFY_CAPACITY = 64;         

//当桶中的数据被树化时最小的hash表容量(如果没有达到这个阈值,即hash表容量小于MIN_TREEIFY_CAPACITY,当桶中bin的数量太多时会执行resize扩容操作)这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍。

 

桶中的每个数据是Node<k,v>的实例,其中包含Node(int hash,K key,V value, Node<K,V> next);  也就是说桶中的元素所包含这些属性

Node 是 hashMap中的一个内部静态类,他的初始定义如下:

他的内部重写了equals和hashcode方法

 static class Node<K,V> implements Map.Entry<K,V> {
         // 键的hash值
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

我们一般使用hashmap  实例化使用无参的构造方法, 只是初始化和负载因子

还有其他三种种构造方法,分别为其指定桶的大小,桶的大小和负载因子,将一个新的map填充进去

构造方法在下一章讲解  一并讲解tableSizeFor方法

2.put方法  (重点)

HashMap中我们用的最多的就是put,get方法了。

在这之前我们先了解一下put方法所相关的两个方法

hashmap在初始化的时候不会去初始化Node<k,v> []  table   只有在你往map中添加值的时候他才回去判断table有没有被初始化,没有则去初始化,并设置默认大小;

初始化: 红色 注释是初始化过程要执行的

(1).有关桶的初始化和size的扩充()

final Node<K,V>[] resize() {
        Node<K,V>[] oldTab = table;    //让oldTab和table引用同一内存空间
        int oldCap = (oldTab == null) ? 0 : oldTab.length;  //判断当前桶数组是否被初始化过  若没有 则让old(容量)等于0
        int oldThr = threshold;      
        int newCap, newThr = 0;
        if (oldCap > 0) {
                 //这次操作是在扩充数组
                 //当容量扩充到大容量时,将阈值也设置为最大 ,也就是说当size到达阈值的时候在进行扩充,但是下次真的到达可能就不能扩充了
             if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;  //阈值设置为int能达到的最大值
                return oldTab;
              }
               //先让新的容量等于旧容量二倍 之后新容量没到达最大值, 并且之前容量大于等于初始化大小则将阈值扩大二倍
    	     else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold 
		} 
	 else if (oldThr > 0) // initial capacity was placed in threshold
		//如果旧的阈值大于0, 则赋值给新的容量 在这里操作的前提是在初始化hashmap时调用的是带参的构造方法,
              //设置过阈值,但是阈值实际是容量值 详情请看在带参初始化时调用tableSizeFor方法
		newCap = oldThr;
	 else { 
		//桶数组没有被初始化过,且初始化hashmap时调用的是无参构造 // zero initial threshold signifies using defaults
              //容量大小为默认
     		 newCap = DEFAULT_INITIAL_CAPACITY;
               // 计算新的阈值
            	 newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); 
		} 
	if (newThr == 0) {
           //这里主要是在oldThr>0之后会到这里来 ,因为之前的阈值实际上是容量值所以要重新计算新的阈值,并判断大小
    	    float ft = (float)newCap * loadFactor;
	    newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); 
	} 
	threshold = newThr;
        @SuppressWarnings({"rawtypes","unchecked"})
             //申请新大小的桶数组
         Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
           //并且将新的空间赋值给原始桶数组
 	table = newTab; 
	if (oldTab != null) {
	//因为扩充之后 需要给新的数组进行赋值
             for (int j = 0; j < oldCap; ++j){
		 Node<K,V> e;
		 if ((e = oldTab[j]) != null) { 
			oldTab[j] = null; 
			if (e.next == null) 
			   newTab[e.hash & (newCap - 1)] = e;
		        else if (e instanceof TreeNode) 
			 ((TreeNode<K,V>)e).split(this, newTab, j, oldCap); 
			else { // preserve order
				//在这里遍历链表 并且将值存放入 新的table中
				//这里的代码分析主要在另一篇文章中讲解
                     		  Node<K,V> loHead = null, loTail = null; 
				  Node<K,V> hiHead = null, hiTail = null; 
				  Node<K,V> next;
			   do { next = e.next; 
				if ((e.hash & oldCap) == 0) { 
					if (loTail == null) 
						loHead = e; 
					else 
						loTail.next = e; 
					loTail = e; 
				} else { 
					if (hiTail == null) 	
						iHead = e; 
					else 
						hiTail.next = e; 
					hiTail = e; 
				}
			   } while ((e = next) != null);
			 if (loTail != null) {
				 loTail.next = null; 
			         newTab[j] = loHead;
			   } 
		         if (hiTail != null) { 
				hiTail.next = null; 
				newTab[j + oldCap] = hiHead; 
			}
    		 } 
		}
	     } 
	}
   //返回新数组
 return newTab;
 }




(2).hashmap中hash值获取方式

 static final int hash(Object key) {
        int h;
      //如果他的主键为null则hash值0,也就是hashmap允许键为null,但只是存在一个
      //如果主键空,获取他的主键不为空,则获取他的hashcode值,并将hashcode值无符号右移16位之后按位相异或
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

// 我们在put的时候,传入的是String类型的键值,存放的就是String类型吗?

我们一步一步深入解析

public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

这是put()方法的源码,主要操作在putVal中,

Put方法的执行过程大致是这样的,取得键值,并取得到键的hash值,根据hash&(数组长度-1)作为索引寻找桶的位置,然后检测该索引下是否存在值,没有,将Node(前边有相应的构造方法)类型的值加入参数已注入,若有,先判断他们的hash值是否一致(不同的hash值&相同值可能存在 结果一致,即索引一致)并且键值是否一致,若都一致,则覆盖对应的位置Node里边的值,并将原来的值返回,若不相等,遍历链表,若一直没有满足要求的值,则将当前Node存储在当前位置的桶中,并且将指针指向原来链表的首部。


 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;
         //如果当前桶数组中没有和put进来的键发生hash碰撞,
        if ((p = tab[i = (n - 1) & hash]) == null)
 		//将该Node 放入对应的桶中    
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
     //桶中已存在对应hash值,键值也相同
          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;
                 //没找完且没找到,则继续找,然当前引用指向下一个引用(c 语言链表的遍历)
                   p = e;
                }
            }
    //如果桶数组或者链表中存在和当前的Node键相等的
            if (e != null) { // existing mapping for key
                V oldValue = e.value;

        //如果允许覆盖值,或者之前的值为空      
  if (!onlyIfAbsent || oldValue == null)
                //覆盖
            e.value = value;
             //供LinkedHahMap继承使用的
            afterNodeAccess(e);
            //返回旧值
            return oldValue;
            }
        }
    
    // modCount字面意思就是修改次数
         ++modCount;
//即不存在碰撞 将Node放入桶表中 
//如果当前桶数组的size达到阈值,扩展
  if (++size > threshold)
     resize();
//供LinkedHahMap继承使用的 
afterNodeInsertion(evict); 
return null;
 }





HashMap中put()方法实现原理 突然想解剖HashMap实现原理,Map链表的作者源码如何实现?也可以丰富一下自己的编程思想,也想让读者看见如何观看别人源码的思路和方法。所以心血来潮的我,就来解析HashMap底层原理! 送给读者的话:一个合格的程序员一定要学会观看别人代码。这样子自己的开发也会很多思路和方法。希望国内软件开发越来越好。 首先看类 public class HashMap&lt;K,V&gt; ... 阅读详情

相关推荐

说一下HashMap的put方法

文章目录前言一、HashMap是什么?二、HashMap的put方法1.HashMap中的基本属性2.put方法总结 前言 日常开发中经常使用到HashMap的put方法,本章就从HashMap的源码分析put方法的原理 提示:以下是本篇文章正文内容,下面案例可供参考 一、HashMap是什么? 简单的理解,HashMap就是一个存放k,v键值对的容器 二、HashMap的put方法 1.HashMap中的基本属性 从源码中可以看到,继承了AbstractMap,同时实现了Map,Cloneabl..

weixin_38289612的博客 1948

HashMap详解-内部实现原理(1)-数组和桶

HashMap 是 Java 中非常常用的数据结构,在实际开发中被广泛使用,经常被用于集合框架、程序开发、数据库连接、实现缓存与并发的情况,与ArrayList、HashSet 等同为常用集合的一员,所以对HashMap的了解是必要的。hashmap的初始容量是16,在第一次put的时候进行的扩容初始化,链表长度大于8时才会转换为红黑树,红黑树长度小于6时会退化为链表,扩容因子(就是loadFactor)是0.75,初始化扩容阈值为大于12。表的大小由初始化时指定的容量决定,它的长度是固定的。

qq_18884633的博客 1206

深入解析 HashMap 的 put() 方法及其相关实现

在 Java 编程中,HashMap 是一个非常常用且高效的集合类,用于存储键值对。它基于哈希表实现,提供了快速的插入、删除和查找操作。本文将深入探讨 HashMap 的 put() 方法及其相关的核心内部方法,包括如何处理哈希冲突、链表到红黑树的转换以及扩容机制。通过理解这些细节,你将能够更好地利用 HashMap 来优化你的应用程序,并解决可能出现的性能问题。先来看下hashMap插入数据的大致流程,以便我们接下来理解源码。

qq_41934990的博客 1826

HashMap总结

hashmap总结

qq_23412557的博客 1297

ArduSub程序学习(1)——ardupilot框架整理

AP_HAL层(硬件抽象层)是我们制作 ArduPilot 的方式可移植到许多不同的平台。有一个顶级AP_HAL libraries/AP_HAL,用于定义代码其余部分的接口 有针对具体的板子特性,然后就有了AP_HAL_XXX 子目录,例如,AP_HAL_AVR 用于基于 AVR 的 开发板,AP_HAL_PX4用于 Pixhawk 开发板和 AP_HAL_Linux 基于 Linux 开发板。工具目录tools directories工具目录是杂项支持目录。

weixin_49839886的博客 2812

智能检查点优化:动态频率与差异化存储的断点续训实践(模型训练丨容错机制丨人工智能)

本文深入探讨了大规模模型训练中智能检查点优化的核心实践。针对传统固定频率保存导致的存储浪费与恢复缓慢问题,提出了基于损失变化率的动态频率算法与分层差异化存储策略。通过PyTorch代码示例,详细展示了如何实现动态调度与增量保存,有效降低存储成本,并确保训练中断后能快速、可靠地恢复,显著提升训练任务的容错能力与经济效益。

weixin_29072299的博客 333

HashMap解读

HashMap源码简单的阅读

zhangshuai66的博客 1380

时序约束实战:从setup/hold到时钟路径约束的深度解析

本文深度解析数字设计中的时序约束实战,重点探讨如何从setup/hold检查的核心原理出发,理解并应用时钟路径约束。文章通过剖析Path Requirement的计算逻辑,结合同频、倍频及异步时钟域等典型场景,提供了从解读时序报告到编写、调试SDC约束的系统方法,帮助工程师有效应对复杂SoC设计中的时序收敛挑战。

weixin_29291185的博客 105

HashMap底层原理分析

HashMap底层原理分析

m0_69468924的博客 389

营销反作弊之 异常行为分析模型(一),附带python代码

通过对用户行为进行深入的分析,识别出与常规模式不符的异常行为,可以有效检测并阻止虚假广告点击、刷单、点击欺诈等欺诈行为。本文将详细探讨营销反欺诈中异常行为分析的方法,介绍如何通过数据采集、清洗、行为建模与异常检测,准确识别潜在的欺诈行为,并提供 Python 实现代码示例。**监督学习 (Supervised Learning):**在标注数据的帮助下,训练机器学习模型使其能预测未知数据的结果。营销反欺诈异常行为分析的整体流程涉及多个环节,确保通过对用户行为的深入分析,及时识别潜在的欺诈行为。

viviwiky的博客 1230

PCL DBSCAN密度聚类【2026最新版】

点云密度聚类的PCL代码实现,与matlab自带的密度聚类算法进行对比验证,结果一致。3万多个点能再2秒左右运行出结果,算法效率尚可。

点云侠的博客 5681

Map详解

Map简介 Map的常用实现类如下: Hashtable:线程安全,不支持null键和值,性能不如ConcurrentHashMap; HashMap:最常用的哈希表实现,非线程安全,支持null键和值; TreeMap:基于红黑树的提供顺序访问的Map,自身实现了key的自身排序,也可以指定Comparator来自定义排序; LinkedHashMap:HashMap的子类,保存了记录插入的顺...

tangent2020的博客 473

【超详细】计算机组成原理总结及思维导图

计算机组成 第一章 计算机系统概论 冯诺依曼型计算机特点 1.计算机由运算器,控制器,存储器,输入和输出设备5部分组成 2.采用存储程序的方式,程序和数据放在同一个存储器中,并以二进制表示。 3.指令由操作码和地址码组成 4.指令在存储器中按执行顺序存放,由指令计数器(即程序计数器PC)指明要执行的指令所在的储存单元地址,一般按顺序递增,但可按运算结果或外界条件而改变 5.机器以运...

圣三一 10万+

源码解析HashMap的put方法

本篇文章将从源码的角度来很详细地讲解HashMap中put方法的执行流程。

深夜无眠的博客 1904

YOLOv13改进策略【Backbone/轻量化】| 替换骨干网络 CVPR-2024 StarNet,超级精简高效的轻量化模块

本文记录的是。StarNet设计简洁,没有复杂的设计和精细调整的超参数,仅是一个 4 阶段的分层架构。并且其中能够在低维空间计算的同时考虑极高维的特征这一特性,进而提高模型精度。本文在替换骨干网络中配置了原论文中的starnet_s1starnet_s2starnet_s3和starnet_s4七种模型,以满足不同的需求。

Limiiiing的博客 669

第14.7章 高翔博士最新开源框架Lightning-LM源码解读(七):PoseExtrapolator模块深度剖析,揭秘激光SLAM高频位姿外推核心技术

PoseExtrapolator是Lightning-LM框架中负责高频位姿外推的核心模块,通过融合DR(航位推算)、激光里程计和PGO(位姿图优化)数据实现精准实时定位。模块初始化依赖PGO数据,后续通过DR数据进行高频位姿更新,并利用PGO结果进行误差补偿。关键函数AddDRLocAndExtrapolate处理DR增量位姿,结合速度补偿机制逐步修正误差,保证高频输出的同时提升精度。该模块体现了多传感器融合思想,通过互补性数据(高频DR与低频高精PGO)实现鲁棒定位,代码中使用了SE3位姿表示、互斥锁保

行知SLAM 348

解析HashMap中的put方法

引言 在Java集合中,HashMap的重要性不言而喻,作为一种存储键值对的数据结构,它在日常开发中有着非常多的应用场景,也是面试中的高频考点,本篇文章就来分析一下HashMap集合中的put方法。 HashMap底层数据结构 先来了解一下HashMap底层的数据结构,它实质上是一个散列表,在数据结构课程中,我们应该都学习过散列表,它是通过关键码值而直接进行访问的一种数据结构,比如存储这样的一个序列:5,12,7,6,1,3。我们首先需要设定一个hash函数,通过该函数就能够定位每个元素存储的位置,比如ha

。。。 6740

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

HashMap第2讲——put方法源码及细节

上篇文章介绍了HashMap在JDK 1.8前后的4大变化,今天就进入到put方法的源码解析。HashMap的设计非常巧妙,细节也很多,今天来看看部分细节,后续的文章会一一介绍。 ps:学习源码的目的不仅仅是为了了解它的运行机制,更重要的是学习它的思想和编码技巧,每一行的源码都可能都经过了“千锤百炼”,才得以呈现在大家眼前。

让~学习~成为一种习惯(橡 皮 人の技术博客) 1208

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

HashMap的put方法源码解析

通过上述流程,HashMap实现了高效的键值对存储与检索,设计上兼顾了时间复杂度与空间利用率。:数组容量翻倍(如16→32),并重新计算阈值(新容量 = 旧容量。遍历旧数组,将每个元素重新哈希到新数组(重新计算每个节点的索引)。创建默认容量16的数组,阈值(threshold)为。:更新对应节点的Value,并返回旧值47。将链表转换为红黑树(否则仅扩容数组)48。的Map实现,用于存储键值对。,确定键值对在数组中的存储位置。方法,按红黑树规则插入新节点。:将新节点插入链表末尾。,但位运算效率更高。

qq_40453972的博客 597

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Hashmap 的源码解析以及put流程

一.Hashmap的定义 Hashmap是一种常用的数据结构,底层是基于数组和链表实现的。 二.Hashmap的详情结构 2.1 数据结构 HashMap提供了三个构造函数: HashMap():构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。 HashMap(int initialCapacity):构造一个带指定初始容...

健康平安的活着的专栏 4911

HashMap源码分析:Put流程,扩容流程

hashmap面试题,hashmap的put源码及流程,hashmap的扩容源码及流程

aquriushu的博客 1036

HashMap的put方法的源码分析

当插入新的键值对时,HashMap会根据键的哈希值来确定其在哈希表中的位置。2. 获取哈希表中的桶位置:根据计算出的哈希值,我们可以通过位运算得到哈希表中的桶位置。3. 遍历链表,查找是否已存在相同的键:在哈希表中,每个桶位置可能包含一个链表,用于解决哈希冲突。4. 创建新的键值对并插入链表头部:如果在链表中没有找到相同的键,就需要创建一个新的键值对,并将其插入链表的头部。7. 返回null,表示插入成功:最后,如果插入的键不存在于哈希表中,put方法会返回null,表示插入成功。否则,返回null。

N201871643的博客 716

解读HashMap中put方法的源码

由于重写了hashCode方法,致使strKey的hashCode和 strKey2的hashCode相同,但是他们equals的结果却不相同,这里使strKey和strKey2的hashCode相同的目的是为了制造散列冲突(散列冲突指的是 ”桶“ 已经被填充的现象,也就是元素对应的node数组下标的位置已经有值了),即由于hashCode相同导致不同的元素存放在node数组的同一位置,要注意hashCode即便是相同的也会出现散列冲突,这里只是为了模拟散列冲突所以设置了相同的hashCode。

qq_45593903的博客 1260

HashMap源码解析:PUT流程详解

HashMap源码解析摘要 HashMap是基于哈希表的Map接口实现,采用数组+链表/红黑树结构存储键值对。默认初始容量16,负载因子0.75,当链表长度超过8且数组长度≥64时会转为红黑树。PUT操作核心流程:1)计算key哈希值;2)通过(n-1)&hash确定数组索引;3)处理哈希冲突(链表尾插/红黑树插入);4)必要时扩容。扩容时采用2倍扩容机制,将旧数组元素重新分配到新数组。迭代器采用fail-fast机制保证线程不安全时的快速失败。哈希计算通过key.hashCode()高16位异或运

小电玩 777

HashMap put()方法源码解析

HashMap put()方法总结: ①.判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容; ②.根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如果table[i]不为空,转向③; ③.判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向④,这里的相同指的是hashCode以及equals; ④.判断table[i] 是否为treeNode,即table[i] 是否是红

weixin_42418334的博客 518

源码梳理(5)HashMap的put方法

源码使用的是JDK17HashMap的数据存放简述1 HashMap中存在一个属性名叫table的哈希表,结构类型是数组2 哈希表这个数组,它的每一个下标位置存放的是Node类型的链表的首节点(链表在一定条件下会转为红黑树)3 每一个Node实例都会有key和value的属性值,对应的是HashMap中的一条数据(也可以说一个Node就是一条数据)

SuperrWatermelon的博客 779
上一篇: 关于HTTP协议的相关内容
下一篇: HashMap源码解析《二》
Embra_ce
博客等级 码龄9年 2粉丝 19原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值