当HashMap在初始化没有指定容量的情况下,首次添加元素时,数组的容量为16;当超出阈值,数组容量为扩容为之前的2倍。
为什么HashMap每次扩容都是之前的2倍?而不是像ArrayList首次为10,后续为1.5倍呢?2倍不是很浪费空间吗?
HashMap的putVal方法源码,如下图所示:
![](https://i-blog.csdnimg.cn/direct/ede6e06fdc5945268d5ef56a6dff3f73.png)
其中 n 为数组的长度,n - 1 为数组的最大索引值。(n - 1) & hash
的意思是将每个元素的key的hash值,与最大索引值-1进行相与操作,得出该元素在数组中的位置。hash
是添加的元素进过哈希函数计算出来的值。
每次扩容后的数组长度如下表:
与运算的规则如下,只要有一个0,结果就是0;两个同时为1,结果才是1。
1 & 0 = 0
0 & 1 = 0
1 & 1 = 1
0 & 0 = 0
假如HashMap的容量不是2的n次幂,设容量为10,二进制为01010,(n-1)的二进制是01001,向里面添加同样的元素9,12,13,15,结果为:
可以看出,9,13,15得出的结果都是9,index相同,hash碰撞严重。
当HashMap的容量是16时,它的二进制是10000,(n-1)是15,二进制表示是01111,和hash值9,12,13,15进行与运算,计算结果如下:
还是9,12,13,15。可以看出,与运算后得出不同的值,使得添加的元素能够均匀分布在集合中不同的位置上,避免hash碰撞。
综上所述,HashMap计算添加元素的位置时,使用的位运算,这是高效的运算;
另外,HashMap的初始容量是2的n次幂,扩容也是2倍的形式进行扩容,是因为容量是2的n次幂,可以使得添加的元素均匀分布在HashMap中的数组上,减少hash碰撞,避免形成链表的结构,使得查询速度降低!