threshold函数_HashMap初始化时的Capacity、loadFactor与threshold

从hashMap的构造函数开始:

72c6bc63385f13bbe1bc6ef45e1ed1cd.png

initialCapacity:初始化容量,默认16

loadFactor:装载因子,默认0.75

构造函数的最后以initialCapacity做入参调用了tableSizeFor方法,来看下这个方法的作用:

d89da1071fed5c2f9b440c815f34c041.png

返回给定目标容量的二次幂,也就是返回比入参大的最小的2的n次幂。

例如:传入8,返回8;传入9,返回16.

其中,|=为或等运算符,>>>为无符号右移,源码写这么高级为了速度?

由tableSizeFor得到threshold:扩容的阈值,下面看一下它的注释

3927ff6fd88028383f65f87bfddff13f.png

要调整大小的下一个size值,capacity * load factor 即容量*装载因子。

例如:当前map的容量为16,则map的size达到16*0.75=12时,即需要扩容。

到这时,构造函数已经执行完了,心中仍然有两个疑问,一是hashmap的容量capacity并没有被初始化,整个构造函数仅仅使用用户传入的initialCapacity定义了threshold的值。二就是threshold并不是如注释中所写的capacity * load factor。

我们反射调用看一下map的容量:

ac416649de875233badcc529353f1e0f.png

为什么,我们传入的3,而hashmap最终的容量是4呢?看一下capacity方法:

a450e66ab218e52ea602083763dec6ef.png

最终返回的还是threshold,大于入参的最小的2的n次幂。

个人见解:hashmap的容量在初始化时就是我们实际传入的值,并没有运算后设置为2的次幂,真正的设置容量发生在put操作时。(每个jdk版本的实现存在差异,我大学时期看1.6版本的集合源码,现在看1.8版本时发现的,但是这里不重要)

结合着第二点疑问,threshold什么时候和容量与装载因子关联起来的?我们来看一下put操作发生了哪些事:

2f0335b591e740441849cf25a3eab7d3.png

当table==null时,执行了resize()方法,这个就是扩容的方法。

为什么这时要扩容呢?看一下里面做了什么操作:

2fdcbb25fc2b5bcf39bc0edb0fc5414c.png

这一系列标红的if-else操作,最终致使threshold=threshold*loadFactor,注意理清思路:在执行第一次resize()前,threshold仍然是构造函数中的比入参大的最小的2的n次幂,到这时threshold才真正担当起它扩容阈值的职责(致谢王泽龙同学的友情指导)

到这里,整个hashmap的初始化阶段已经梳理透彻,接着你对它crud时就回到上上一张图的putVal()方法,++size>threshold时,resize()。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值