Java Collection框架(六)HashMap源码浅析

java学习——Fastutil之Object2ObjectOpenHashMap 两者核心差异源于哈希冲突处理机制HashMap通过链地址法提供更稳定的高冲突处理能力,而通过开放寻址法优化内存和低冲突场景性能。开发者需根据数据特征(如冲突概率、内存限制)和操作类型(查询/更新频率)选择合适实现。 阅读详情

 Java Collection框架 HashMap 源码解读 与 实现原理浅析

​

2018拍摄于京都天龙寺

微信公众号

 

王皓的GitHub:https://github.com/TenaciousDWang

 

 

今天来看平时最常用的一个容器HashMap,版本为JDK8.

 

数据结构

 

JDK8 之后的HashMap底层在解决哈希冲突的时候,除了使用数组加上单链表外,还加入了红黑树结构,因为当处理如果 hash 值冲突较多的情况下,链表的长度就会越来越长,时间复杂度达到 O(n)。

 

所以JDK7之后,在满足条件的时候,就会在添加元素的同时将原来的单链表转化为红黑树,查询的时间复杂度是 O(logn) ,可以更高效的对 HashMap 中的元素进行操作。后面会单独拿出一个篇幅来复习红黑树。

 

 

HashMap的数据结构如上图(哈希桶包含哈希槽,这里为了好区分自己画图分开了)。我们先来看几个概念。

 

table数组,用来存储所有节点数据的数组,数组中table[i]的位置对应一个哈希槽,底层数组的长度总是 2^n。当向HashMap集合中放入键值对时,对key进行hash运算找到一个地址对应一个哈希槽,这个元素存到哈希槽对应的哈希桶中,但是hash计算无法避免哈希冲突,多个元素落入同一个哈希槽中时,就会在哈希桶中形成链表,链表的头部节点放在了哈希槽中。

 

哈希桶中的所有元素的总和就是HashMap的size,遍历HashMap元素,首先横向遍历所有哈希槽(table[0]~table[length-1]),如果哈希槽中有元素,就遍历桶里所有元素。

 

JDK7之后,对HashMap进行了改造,当哈希桶中的元素超过8个且table数组的长度大于或等于64时,会将桶中的链表转换为红黑树,来优化和提高性能。桶中元素小于6时,会由红黑树转为链表形式。

 

大概了解HashMap的底层数据结构后,我们开始看看HashMap的源码,首先看几个重要的成员变量。

 

重要的成员变量

 

 

DEFAULT_INITIAL_CAPACITY初始化容量,1<<4,这里为了提高效率,HashMap里的运算使用位移运算,向左移动4位,2^4=16,16代表了初始化table数组的长度,也就是哈希桶的数量。

 

MAXIMUM_CAPACITY最大容量,2^30,桶的最大数量。

 

DEFAULT_LOAD_FACTOR负载因子,0.75f,在扩容前,允许容量自动增加。由于扩容会增加原来哈希桶数量的两倍,有可能会造成浪费,所以设置一个负载因子,假设要存储12个元素,此时桶的数量会自动增加到12/7.5=16,16表示当前默认容量大小,这时并不会触发扩容,当存入第13个元素时,13>16*0.75,次时触发扩容条件,容量变为32。当集合元素数量>当前容量*0.75时触发扩容。

 

 

TREEIFY_THRESHOLD树化阈值,哈希桶中元素数量大于8时,进行树化(桶数量大于等于64时)。

 

UNTREEIFY_THRESHOLD反树化阈值,哈希桶中元素数量小于6时,由红黑树结构变为链表结构。

 

MIN_TREEIFY_CAPACITY最小树化容量,桶数量大于等于64时触发树化条件,再根据TREEIFY_THRESHOLD树化阈值判断桶中数据是否需要树化。

 

构造方法

 

 

第一个方法可以自定义初始化容量与负载因子,第二个方法只自定义初始化容量使用默认负载因子,第三个为默认构造方法,只赋值负载因子,第四个方法为根据指定Map构造一个新的HashMap,使用默认负载因子。

 

初始化容量方法调用了static final int tableSizeFor(int cap)。

 

 

这个算法看的一脸懵逼。。。实际上这个方法是在找大于等于cap且最小2的幂。

 

假设cap为9,int n =8;8的二进制位为1000,8向右移位1个单位,二进制变为0100,相当于8/2=4,1000对0100做位或运算得1100

 

接下来1100向右移动2个单位得0011,做位或运算得1111

 

接下来1111向右移动4个单位得1111,做位或运算得1111

 

接下来1111向右移动8个单位得1111,做位或运算得1111

 

接下来1111向右移动16个单位得1111,做位或运算得1111

 

1111为十进制15,最后n+1为15+1得16,所以得到大于或等于9的最小2次幂数16。

 

这里印证了table的大小总是2^n的,初始化容量总是根据设定容量去找大于等于它的最小二次幂数。

 

基础哈希节点Node<K,V>

 

接下来我们看一下HashMap里面用于存储的基础单位Node类,这是一个HashMap中的静态内部类,JDK8后加入了红黑树机制,本篇先不涉及到,与红黑树一起来说。

 

 

可以看到Node<K,V> implements Map.Entry<K,V>,构造器参数有四个,分别对应其成员变量。

 

final int hash; 为元素key值经过hash计算得出的结果,一会我们会看HashMap类中的hash方法。

 

final K key; 与 V value; 这个是元素原始key值与value。

 

Node<K,V> next; 用来记录下一个节点,链表用,与我们之前LinkedList里面的Node内部类已经完全不一样了。

 

Node<K,V>节点覆写了Object的hashCode与equals和toString方法。

 

getKey(),setValue(),getValue()为操作元素的方法。

 

hash函数

 

用于计算元素key值的哈希槽地址,即确定table数组中哈希槽的位置。

 

 

key为null时返回0,key不为null时,首先调用Object的hashCode方法计算哈希值返回,Object的hashCode方法调用的本地的native方法会根据内存地址计算返回一个整数值,整数值>>>16无符号右移16位后与整数值本身做异或运算得到hash值。

 

只进行一次位运算,一次异或运算,获得key的hash值。

 

public V put(K key, V value)

 

Node<k,v>节点与hash函数看完后,我们来看HashMap如何put一个元素。

 

 

实际上调用了putVal(hash(key), key, value, false, true);方法。

 

 

首先判断是否是第一次添加元素,如果是,则先使用resize方法进行扩容。

 

i = (n - 1) & hash用于计算哈希槽位置即table数组的指针位置,这里用数组长度-1后做与刚才得到的hsah整数值&位与运算得到table数组指针位置。

 

如果当前数组指针元素为空,那么直接创建Node节点放入该哈希槽。

 

 

 

如果不为空,则表示发生了哈希碰撞,首先判断key值是否相同,如果相同则直接覆盖Node节点。

 

如果key值不相同则先判断节点P是否为红黑树节点,如果是则需要先创建新节点为红黑树节点TreeNode进行插入操作,如果不是跳过。

 

然后,开始遍历p节点所在哈希槽对应哈希桶内的链表,到链表的底部,创建一个新的节点放到p节点的next变量中,即链表尾部,break跳出循环,如果链表中有相同的key值节点则直接替换。

 

最后如果需要替换节点即e节点不为空记录了旧的节点,返回旧节点的value值。

 

 

收尾,记录modCount操作次数+1,size+1如果size大于阈值即当前容量*0.75时触发resize方法进行扩容。

 

其他put元素的方法原理基本相同,感兴趣大家可以自行查看源码。接下来我们来看HashMap中重要的扩容方法resize。

 

final Node<K,V>[] resize()

 

Node<K,V>[] oldTab = table;将当前table赋值给oldTab。

 

int oldCap = (oldTab == null) ? 0 : oldTab.length;旧容量

int oldThr = threshold;将全局阈值赋值给oldThr

int newCap, newThr = 0;初始化扩容新容器的容量及阈值。

 

当oldCap大于0,先判断是否大于等于最大容量2^30,如果大于等于则无需扩容了,直接返回老table,扩容阈值赋值Integer.MAX_VALUE。如果没有大于最大容量且oldCap大于默认容量,则用位运算向左移1位,即*2,oldThr*2赋值给newThr新的扩容阈值。

 

当oldThr>0时,表示阈值计算过,则直接将oldThr旧扩容阈值赋值给newCap新容器的初始化容量。

 

都不是则全部赋上默认值。

newCap=DEFAULT_INITIAL_CAPACITY;

newThr=(int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);

 

如果newThr==0,则重新计算扩容阈值赋值给newThr。最后将newThr赋值给HashMap容器的全局阈值。threshold = newThr;

 

上述为扩容第一步,即确定新容器的容量及新容器的阈值。接下来为第二部赋值旧容器中的元素到新的容器中。

 

 

根据新newCap容量创建newTable数组,讲newTable赋值给HashMap的全局table变量。

 

如果oldTab为null则不用复制,直接返回新的空的table数组。如果存在,就开始遍历oldTab数组,开始复制元素到全局table中。

 

先e = oldTab[j]赋值,oldTab[j]不为null,就先清空oldTab中j位置的元素释放资源,e.next == null表示当前哈希槽只有一个元素,不是链表形态,直接重新计算e节点的hash槽地址,直接存入,newTab[e.hash & (newCap - 1)] = e;

 

如果为e类型为TreeNode,则需要使用红黑树节点用方法去确定节点在新容器中的位置。

 

 

                        Node<K,V> loHead = null, loTail = null;

                        Node<K,V> hiHead = null, hiTail = null;

 

链表状态下,由于对原来的容器进行了双倍扩容,为了table中元素在哈希槽分布均匀,效率更高,原来的元素可能存到原来table数组中的哈希槽中,源码中定义为low位,loHead定义低位头节点,loTail定义低位尾节点,原来的元素也可能存到扩容后的哈希槽中,源码中定义为high位,hiHead 定义为高位头节点,hiTail 定义为高位尾节点,next定义原oldCap中节点的next节点。

 

开始do while 循环直到链表的尾部,每次对链表中的节点元素进行e.hash & oldCap运算,获取元素的hash值与oldCap原来容器的做位与运算。等于0时放入低槽位,反之放入高槽位。

 

新的hash值根据扩容的table大小-1重新计算,只需要看看比原来的hash值新增的那个bit是1还是0,是0的话索引没变放到底槽位,是1的话索引变成原索引加上oldCap来放入高槽位。

 

              //将低位链表存放在原哈希槽

              if (loTail != null) {

                  loTail.next = null;

                  newTab[j] = loHead;

              }

              //将高位链表存放在新哈希槽

              if (hiTail != null) {

                  hiTail.next = null;

                  newTab[j + oldCap] = hiHead;

              }

 

到此,第二部将oldTab中的所有元素移动到了newTab中,扩容结束。

 

public V get(Object key)

 

接下来看一下get方法。

 

 

如果获取节点为null则返回value为null,这里调用了getNode方法。

 

 

首先使用hash函数计算key值,tab[(n - 1) & hash]哈希槽桶内元素就一个直接返回。

 

如果哈希桶内为红黑树则调用专用getTreeNode方法从树中找到对应元素返回。

 

如果是链表则遍历链表找到后返回。

 

public V remove(Object key)

 

接下来看一下HashMap删除元素的方法。

 

 

调用removeNode方法删除节点。

 

 

首先判断table数组是否为空,数组长度是否大于0 ,对应的哈希槽上是否有元素。

 

Node<K,V> node = null, e; K k; V v; 造一个空的元素用来盛放要删除的元素,如果哈希槽中只有一个元素则将该元素直接赋值给node。

 

如果为红黑树则使用getTreeNode找到元素赋值给node。

 

如果为链表则遍历链表找到元素赋值给node。

 

最后开始删除元素,红黑树使用removeTreeNode方法,如果哈希桶中只有一个元素则直接使用node.next赋值给tab[index],链表则将p.next = node.next。

 

操作次数+1,afterNodeRemoval方法在HashMap中没有实现。

 

最后返回被删除的node。

 

其他方法原理都是基于这一套数据结构来进行操作,所以这里不再赘述,感兴趣的朋友可以自行查看源码。

 

HashMap的数据结构和源码比ArrayList或LinkedList复杂了很多,下一篇我们将继续来看本篇中提到的红黑树。

 

Java集合框架体系结构:深入解析Collection与Map两大体系 Java集合框架是Java语言中用于数据存储和处理的核心库,提供了统一的架构。本文详细解析了Collection和Map两大根接口及其实现类的继承关系、特点和使用场景。Collection接口包括List、Set和Queue三个子接口,分别用于有序集合、无序集合和队列操作。List的实现类如ArrayList、LinkedList和Vector在底层实现、线程安全、随机访问和插入删除等方面各有特点。Set的实现类如HashSet、TreeSet和LinkedHashSet则在排序方式、时间复杂度和允许nul 阅读详情

相关推荐

Java 集合框架:HashMap 的介绍、使用、原理与源码解析

HashMap 根据是一个键值对集合,采用 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。HashMap 最多只允许一条记录的键为 null。HashMap 非线程安全,即任一时刻可以有多个线程同时写 HashMap,可能会导致数据的不一致。如果需要满足线程安全,可以用 Collections 的 synchronizedMap 方法使 HashMap 具有线程安全的能力,或者使用 ConcurrentHashMap。

栗筝i的博客 8725

【Java深入】HashMap的实现原理与源码剖析(一)

一、HashMap的实现原理1.引入毫无疑问,有很多人都用过HashMap,例如HashMap可以接受null键值和值,而HashTable则不能;HashMap是非synchronized;HashMap很快;以及HashMap储存的是键值对等等。2.深入例1:HashMap的get()方法的工作原理?答:“HashMap是基于hashing的原理,使用put(key, value)存储对象到Ha

白夜行 1065

Dynamics 365 On-Premise Server v9.0部署体验

期盼已久的Dynamics 365 On-Premise的版本升级终于在11月初姗姗来迟。 11月2日起已经可以在官方渠道下载正式版的Dynamics 365 Server v9.0安装文件,版本号9.0.2,随手附上中文版安装文件下载地址。 想必已经有不少小伙伴开始尝试各种升级、安装了吧。 Dynamics 365 On-Premise的安装过程,度娘一下已经有很多了,这里就不赘述了,只是...

Roger的专栏 2138

Long2ObjectMap.Entry的用法

Long2ObjectMap.Entry> data; long longData = data.getLongKey(); List objectData = data.getValue(); 得到entry:  Long2ObjectMap> dataMap = new Long2ObjectOpenHashMapSet>> dataSet = dat

开卷有益 2256

机器学习——笔记整理(原理、python代码)——反反复复,出精活!

回顾知识,检查自我,开拓新域。 机器学习1.监督学习 机器学习简介: 机器学习是实现人工智能的手段,其主要研究内容是如何利用数据或经验进行学习,改善具体算法的性能。 多领域交叉,涉及概率论、统计学,算法复杂度理论等多门学科 广泛应用于网络搜索、垃圾邮件过滤、推荐系统、广告投放、信用评价、欺诈检测、股票交易和医疗诊断等应用。 机器学习分类: 机器学习一般分为下面几种类别 监督学习 ( Supervised Learning) 无监督学习 ( Unsupervised Learning) 强化学习(

weixin_45666566的博客 6486

STM32F4系列HAL库配置定时器实验——输入捕获

STM32F4系列HAL库配置定时器实验——输入捕获 输入捕获简单讲解 输入捕获模式可以用来测量脉冲宽度或者测量频率。我们以测量周期和频率为例,用一个简图来说明输入捕获的原理 假定定时器工作在向上计数模式, 图中 t1~t2 时间,就是我们需要测量的高电平时间。测量方法如下:首先设置定时器通道 x 为 上升沿捕获,这样,t1 时刻,就会捕获到当前的 CNT 值,然后立即清零 CNT,并设置通道 x为下降沿捕获,这样到 t2 时刻,又会发生捕获事件,得到此时的 CNT 值,记为 CCRx2。这样,根据定时器

azs0504的博客 9285

比 HashMap 还快 3 倍!

在 get 的时候也涉及到了隐式类型转换 r.nexInt() 返回的类型是 int ,然而 get 需要传入的参数类型是 Object。这里传入的是 k 是 int 类型的,含有隐式装箱 Integer.valueOf(k)还有更快的版本也就是如果 Valude 也是基本数据类型的话可以速度更快。最终的测试结果:fastutil time ms: 602。甚至还有 key 和 value 都是基本数据类型的。因为类型装箱和拆箱带来的性能损失,具体位置是。当然还有其他很多基本数据类型的 key。

leikooo 的个人博客 460

智能体在车联网中的应用:一份详尽到每日的100天学习路线图

这100天的旅程,是一次对毅力、学习方法和工程实践能力的综合考验。它不仅关乎掌握一系列技术点,更关乎培养解决复杂系统性问题的思维模式——将宏观的交通需求分解为微观的智能体决策,再通过多智能体协同涌现出宏观的智能行为。当你完成这份大纲时,你将拥有的不仅是一个项目作品集,更是一套应对“智能体+车联网”乃至更广泛AI+垂直领域挑战的方法论。未来已来,期待你成为构建智能交通新生态的关键贡献者。

IT深耕十余载,大道之简 1332

java之Collection

主要内容 Collection集合 迭代器 增强for List集合 Set集合 学习目标 能够说出集合与数组的区别 说出Collection集合的常用功能 能够使用迭代器对集合进行取元素 能够说出集合的使用细节 能够使用集合存储自定义类型 能够使用foreach循环遍历集合 能够说出List集合和Set集合的区别 能够说出List集合各种实现类的区别 能够说出Set集合各种实现类的区别 能够说出Collection和Map集合的区别 说出Map集合的常用功能 能够遍历Map集

m0_46191714的博客 2万+

手把手教你学simulink(31.31)--双向DCDC电源场景示例:设计并实现一个基于变频控制的双向降压变换

设计并实现一个基于 Simulink 的双向降压变换器,能够在充电模式(从高压侧向低压侧传输能量)和放电模式(从低压侧向高压侧传输能量)之间切换,确保输出电压稳定,并根据负载变化自动调整工作模式。

MHD0815的博客 343

智能制造之物料详解

制造业业务系统中的物料流转贯穿需求、采购、生产到交付全流程,各系统协同实现精准追踪。需求阶段由CRM/ERP/PLM生成物料计划;采购入库阶段SCM/WMS/QMS完成采购质检;生产阶段MES/APS协调领料加工;成品交付阶段WMS/SCM处理出库物流。整个流程以BOM为蓝图,ERP为调度中心,通过数据联动实现物料状态、位置和数量的全链路可追溯。

cdfunlove的博客 654

Java集合框架源码详解系列(一)

之前写过关于 C++ STL 的四篇文章,现在开始写一下关于Java集合框架的文章,该系列博客将会写很长时间。不管是C++的STL也好,Java的集合框架也好,这两者其实都是将一些基本的数据结构进行了封装实现,从现在开始博主将带领大家遨游在Java集合框架的源码世界,准备好了吗?Go!!!

晴空๓ 4298

uniapp - H5人脸识别认证与活体检测功能(纯前端免费方案+微信sdk人脸识别)完整源码,微信公众号网页/h5端人脸识别功能人脸核身(微信方案提供后端spring boot+thinkphp源码

uniapp实现人脸认证,uniAPP h5手机拍照+人脸识别,免费人脸识别插件,前端人脸识别解决方案,uniapp H5人脸识别带前后摄像头,人脸识别在H5页面进行采集,微信公众号H5人脸核身,H5端人脸识别功能实现,免费h5人脸识别插件方案,微信公众号H5网页实现人脸识别,uniapp人脸监测,uniapp人脸生物监测,使用uniapp开发H5人脸采集功能/人脸识别功能,uniapp项目—h5端人脸采集功能实现,uniapp vue3人脸核身,H5活体检测认证,人脸认证张嘴摇摇头指引动作,人脸核身 微信

🏆 前端领域优质创作者 3809

Java 集合框架 源码浅析 与理解

Java集合框架 collection map set hashmap hashset queue

永远不要停下学习的脚步。 7024

YOLOv11改进 | 网络结构代码逐行解析(一) | 项目目录构造分析

Hello,大家好这次给大家带来的不是改进,是整个YOLOv11项目的分析整个系列大概会更新5-7篇左右的文章从项目的目录到每一个功能代码的都会进行详细的讲解,下面开始进行YOLOv11逐行解析的第一篇——项目目录构造分析开头之前顺便给大家推荐一下我的专栏,本专栏更新上百余篇YOLOv11改进机制手把手教你添加到网络结构中,同时针对拿到模型不知道如何修改,不知道如何发表论文的读者进行针对性的文章介绍,本专栏质量分平均分96分,内容质量完全有所保证。

Snu77的博客 1万+

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

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

Java集合框架学习总结(含源码分析)

Java集合框架Java集合框架概述 Java集合框架概述 用作自己学习笔记:如有不当的地方,还请指点~ 首先上图啦:看看Java集合相关类的关系图

渣渣飞的博客 1143

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Java两大集合:Collection 和 Map 源码及总结

----Collection接口:单列集合,用来存储一个一个的对象|----List接口:存储有序的、可重复的数据。一种包含有序元素的线性表可以存放多个null值。可称之为 “动态”数组|----ArrayList:作为List接口的主要实现类,多用于频繁的改查操作,**线程不安全,效率高**|----LinkedList:对于频繁的插入删除操作,**使用此类效率比ArrayList效率高,线程也不安全**|----Vector(不咋用了):作为List的古老实现类,**线程安全,效率低**

2301_79561226的博客 1249

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

浅析JAVA集合框架之HashMap

数据结构

秀强的专栏 1672

Java集合框架解析:从基础到底层源码

单线程环境快速查询:ArrayList/HashMap频繁增删:LinkedList需要排序:TreeSet/TreeMap高并发场景读多写少:CopyOnWriteArrayList写多读少:ConcurrentHashMap严格一致性:Collections.synchronized系列函数式编程使用Stream API进行链式处理优先选择不可变集合(Guava/Java9+)彩蛋知识点。

Hello World!你好世界! 2866

【java集合框架源码剖析系列】java源码剖析之HashMap

前言:之所以打算写java集合框架源码剖析系列博客是因为自己反思了一下阿里内推一面的失败(估计没过,因为写此博客已距阿里巴巴一面一个星期),当时面试完之后感觉自己回答的挺好的,而且据面试官最后说的这几天可能会和你联系来看当时以为自己一面应该是通过的,但是事与愿违,痛定思痛,仔细回顾了一下面试官问我的整个过程,感兴趣的可以参看我的博客:【阿里内推一面】记我人生的处女面。感觉自己回答的不是很好的地方就

(* ̄︶ ̄) 1万+

Collection集合框架学习笔记

Collection集合框架学习笔记(第一次想将自己Typora的笔记搬上优快云与大家分享。。但是这个格式不太适应。。这篇就当记流水账吧。)

7zwang的博客 1071

HashMap源码浅析

文章目录1 HashMap简介2 底层数据结构2.1 JDK1.72.2 JDK1.83 HashMap源码分析(JDK 1.8)3.1 静态属性3.2 成员属性3.3 构造方法3.4 tableSizeFor(int cap)方法3.4 确定数组索引位置3.4.1 hash(Object)3.4.2 桶下标计算公式3.5 put(K,V)3.6 resize()3.7 get(Object)3.8 treeifyBin(Node1 HashMap简介 HashMap 是一个散列表,它存储的内容是键值对(k

Stay Hungry, Stay Foolish! 1400

Collection集合框架

Collection集合框架集合框架接口集合框架主要继承链 集合框架接口 在研究源码的时候,许多人会用面向过程的思路去分析源码。这是一种比较不好的习惯,因此,笔者强调,研究对象时,要多采用“面向对象”的思想。即“继承(接口)决定方法,结构决定算法”,从而在看源码时,能够以“物以类聚”的观点,一叶知秋。 图1 集合接口 图1是官网上JDK8提供的视图,值得注意的是,虽然Map接口不继承于Coll...

彬 1031

java HashMap 源码分析(深度讲解)

java 集合篇章——HashMap源码分析(非常详细)。

优快云 / 稀土掘金/ B站 / GitHub: Cyan_RA9 2559

Java集合框架源码分析:hashMap

特性描述是否允许为nullkey和value都可以取值为null是否允许重复key重复会覆盖,value允许重复是否有序无序是否线程安全非线程安全JDK1.8之前HashMap是由数组 + 链表结构组成,数组是HashMap的主体,链表则是主要为了解决哈希冲突(两个对象调用的hashCode方法计算的哈希码值一致导致计算的数组索引值相同)而存在(拉链法:解决冲突)。JDK1.8以后(包含JDK1.8)HashMap是由数组+链表+红黑树组成。

玉汝于成 1521
上一篇: Java Collection框架(五)集合与泛型 比较器 hashCode与equals
下一篇: Java Collection框架(七)红黑树与TreeNode源码浅析
JavaBoy王皓
博客等级 码龄11年 23粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值