java的hashMap扩容新地址计算的巧妙

what:

  hashmap扩容

    1、重新建立一个新的数组,长度为原数组的两倍(实际长度为2的n次幂);

    2、遍历旧数组的每个数据,重新计算每个元素在新数组中的存储位置(一次性完成);使用节点的hash值与旧数组长度进行位与运算,如果运算结果为0,表示元素在新数组中的位置不变;否则,则在新数组中的位置下标=原位置+原数组长度。

 

why:

  为什么扩容时节点重 hash 只可能分布在原索引位置或者 原索引长度+oldCap 位置呢?换句话说,扩容时使用节点的hash值跟oldCap进行位与运算,以此决定将节点分布到原索引位置或者原索引+oldCap位置上的原理是什么呢?

  

  假设老表的容量为16,则新表容量为16*2=32,假设节点1的hash值为 0000 0000 0000 0000 0000 1111 0000 1010,节点2的hash值为 0000 0000 0000 0000 0000 1111 0001 1010。

  那么节点1和节点2在老表的索引位置计算如下图:

    计算1(16个桶的真实计算),由于老表的长度限制,节点1和节点2的索引位置只取决于节点hash值的最后4位。

    计算2(32个桶的真实计算,扩容1倍后),计算2为元素在新表中的索引计算,可以看出如果两个节点在老表的索引位置相同,则新表的索引位置只取决于节点hash值倒数第5位的值,而此位置的值刚好为老表的容量值16,此时节点在新表的索引位置只有两种情况:原索引位置原索引+oldCap(放大1倍)位置(在此例中即为10和10+16=26)。

    由于结果只取决于节点hash值的倒数第5位,而此位置的值刚好老表的容量值16,因此此时新表的索引位置的计算可以替换为计算3,直接使用节点的hash值与老表的容量16进行位于运算,如果结果为0则该节点在新表的索引位置为原索引位置否则该节点在新表的索引位置为 原索引+ oldCap 位置。

 

posted @ 2022-06-01 16:22  修心而结网  阅读(585)  评论(0编辑  收藏  举报