系列目录#
构造函数#
构造函数:
默认构造函数什么都不做,只是将加载因子设为默认加载因子。
有初始值大小的构造函数,
会将threshold设置为大于输入参数且最近的2的整数次幂的数,比如10,设置阈值16.
即使有initialCapacity参数的构造,也是设置threshold,不会现在设置cap,如要设置cap就需要new资源了,而原理是在等真的插入的时候才去通过resize操作申请内存资源, 见resize.md,put.md
重点:
1.参数最大容量,默认的加载因子,加载因子,阈值
2.哈希桶, Node<K,V>[] table, 是Node数组, 存放链表, 长度初始化时为0, 之后是2的N次方
3.loadFactor和threshold的关系
4.tableSizeFor函数的原理, 见下面解析
默认参数和构造函数源码:
1 | //最大容量 2的30次方 |
tableSizeFor函数的原理#
tableSizeFor的功能(不考虑大于最大容量的情况)是返回大于输入参数且最近的2的整数次幂的数。比如10,则返回16.
1 | static final int tableSizeFor(int cap) { |
先来分析有关n位操作部分:先来假设n的二进制为01xxx…xxx。接着
对n右移1位:001xx…xxx,再位或:011xx…xxx
对n右移2为:00011…xxx,再位或:01111…xxx
此时前面已经有四个1了,再右移4位且位或可得8个1
同理,有8个1,右移8位肯定会让后八位也为1。
综上可得,该算法让最高位的1后面的位全变为1。
最后再让结果n+1,即得到了2的整数次幂的值了。
现在回来看看第一条语句:
1 | int n = cap - 1; |
让cap-1再赋值给n的目的是另找到的目标值大于或等于原值。例如二进制1000,十进制数值为8。如果不对它减1而直接操作,将得到答案10000,即16。显然不是结果。减1后二进制为111,再进行操作则会得到原来的数值1000,即8。
loadFactor和threshold的关系?#
HashMap中size表示当前共有多少个KV对,capacity表示当前HashMap的容量是多少,默认值是16,每次扩容都是成倍的。loadFactor是装载因子,当Map中元素个数超过loadFactor* capacity的值时,会触发扩容。loadFactor* capacity可以用threshold表示。
好多地方都说threshold = loadFactor * capacity, 但有初始值的初始化的时候,threadshold由tableSizeFor函数获得,这个地方之后 threshold 是什么时间进行的调整,应该是之后调整是根据loadFactor* capacity。