说一说HashMap的扩容机制
hashmap初始化时会指定初始化大小以及扩展阈值,如果不指定就使用默认值为null。
当向hashmap中存值时,
如果为空就开始第一次扩容,创建初始化数组大小,默认为16,
如果当前长度大于8且数组长度大于64时,将链表转为红黑树结构,
如果添加的元素达到了阈值的0.75,就进行扩容(默认加载因子是0.75,比如16的容量,就会在16*0.75=12的时候进行扩容)
扩容使用resize方式,每次扩容都是之前的两倍,是使用新数组代替原=原来的旧数组,将原数组的数据迁移到新数组中使用尾插法。
得分点
三个条件、翻倍扩容
参考答案
标准回答
向HashMap中添加数据时,有三个条件会触发它的扩容行为:
每次扩容时都是将容量翻倍,即创建一个2倍大的新数组,然后再将旧数组中的数组迁移到新数组里。由于HashMap中数组的容量为2^N,所以可以用位移运算计算新容量,效率很高。
加分回答
在数据迁移时,为了兼顾性能,不会重新计算一遍每个key的哈希值,而是根据位移运算后(左移翻倍)多出来的最高位来决定,如果高位为0则元素位置不变,如果高位为1则元素的位置是在原位置基础上加上旧的容量。
举个例子,来演示一下数据迁移时,元素在新数组里位置的判定。假设旧数组长度为16(00010000),则翻倍后新数组的长度为32(00100000)。我们从十进制数字上看不出什么,但是从二进制数字却可以看出二者的明显差别,即翻倍后新值的高位多了1。
如果我们把这两个值作为掩码,对key的哈希值做按位与运算,就能求出最高位那一位的差异。如果这一位是0则该元素的位置不变,否则该元素的位置就在原位置基础上加16。这个方式很巧妙,它省略了重新计算哈希值的时间,同时新增出来的一位是0或1是随机的,这样就把产生冲突的节点均匀的分散到新的槽里了。
延伸阅读
如下图,数据迁移的过程,可以参考槽15内的元素的迁移路线进行理解:
另外,HashMap的扩容是通过resize()方法实现的,该方法的关键代码如下: