扩容时空间大小变化:
HashMap中,哈希桶数组table的长度length大小必须为2的n次方(一定是合数),这是一种非常规的设计,常规的设计是把桶的大小设计为素数。相对来说素数导致冲突的概率要小于合数,具体证明可以参考http://blog.csdn.net/liuqiyao_01/article/details/14475159, Hashtable初始化桶大小为11,就是桶大小设计为素数的应用(Hashtable扩容后不能保证还是素数)。
HashMap采用这种非常规设计,主要是为了在取模和扩容时做优化,同时为了减少冲突,HashMap定位哈希桶索引位置时,也加入了高位参与运算的过程。
| 初始容量(默认) | 最大容量 | 扩容时倍数 | 加载因子 |
hashtable | 11 |
| newCapacity= (oldCapacity *2) + 1; | 0.75 |
hashmap | 2^4 | 2^30 | *2 | 0.75 |
hashMap用户自定义长度时,底层会设置长度为大于等于用户提供数的2 的倍数;
扩容时数据的重新分布:
jdk1.8
当table需要扩容时,扩容后的table大小变为原来的两倍,接下来就是进行扩容后table的调整:
假设扩容前的table大小为2的N次方,有put方法解析可知,元素的table索引为其hash值的后N位确定
那么扩容后的table大小即为2的N+1次方,则其中元素的table索引为其hash值的后N+1位确定,比原来多了一位
因此,table中的元素只有两种情况:
元素hash值第N+1位为0:不需要进行位置调整
元素hash值第N+1位为1:调整至原索引+N;
在resize方法中,第45行的判断即用于确定元素hashi值第N+1位是否为0:
若为0,则使用loHead与loTail,将元素移至新table的原索引处
若不为0,则使用hiHead与hiHead,将元素移至新table的两倍索引处
扩容或初始化完成后,resize方法返回新的table