栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

HashMap put(),resize()解析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

HashMap put(),resize()解析

HashMap put(),resize()解析
查看的源码是jdk1.8版本,这里对jdk1.7的HashMap不详细讨论
map常量讲解:

首先,先看看HashMap定义的常量

前三个分别是默认容量=16,最大容量=2^30,默认的负载因子=0.75。当map里的节点大小大于总容量*负载因子时,会进行扩容。
后三个分别是树化长度=8,退化长度=6,以及最小的树化容量=64。jdk1.8中,HashMap的实现是数组加链表加红黑树,当链表长度大于等于8,进行树化,但是首先还要Map的容量大于最小树化容量64,才可以进行树化。

put函数解析

调用put函数,会先通过hash(key)计算key的hash值,onlyIfAbsent的值是指是否允许修改已经存在的key的value值。默认是同意的。代码逻辑如下,传过来的值是false,所以默认就是会替换值。
之后进入putVal函数里面了
如果我们调用newHashMap<>()函数创建Map,一开始的时候,表是没有创建的,所以会先扩容,容量为16。
之后,计算下标(n-1)& hash,计算完了就插入到table表中,如果对应的下标一个节点没有,就直接创建。如果有节点,就遍历判断是不是已经存在key值,如果存在要进行值的替换。如果发现已经是树节点了,就进入树的添加环节。如果遍历到尾部发现还是没有相同的key值,就在尾部添加节点。

当执行完插入过程后,就到了判断是否需要扩容的环节了。先插入,后判断是否需要扩容。

threshold属性的计算是容量*负载因子。可以将threshold理解为扩容的阈值

resize函数解析

resize函数做了两件事情,一是计算新的容量,和新的阈值大小。二是将旧的节点移到新的表。

计算新容量,新阈值,分为三种情况,一是空参创建,二是指定了容量创建,三是已经有表,正常的扩容。
在指定容量创建的时候,也是不创建表的,把容量的数值存放在了threshold属性里。
如果已经存在表了,那就进行正常的扩容过程,容量2,阈值2。如果长度已经大于等于最大容量,就不扩容。
最后就是将旧表中的节点放到新表(table是Node节点类型的数组)中,在这里其实1.8有了一个巧妙的计算下标的方式,如下图

因为length,其实就是容量是保证了其值是2^n的,所以length-1&hash计算下标不会导致下标越界。同时,新的length(新容量)其实就是旧容量左移一位。所以可以巧妙的计算新下标的值要么是原来的,要么是原来的加上旧容量长度。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/462275.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号