为什么HashMap的数组长度是2的幂

  • Post author:
  • Post category:其他



为什么HashMap的长度一定是2的次幂呢?

​ 今天和朋友聊天被问到HashMap的数组长度为什么是2的倍数。说实话挺惭愧的,秋招结束了,还不能完整的给出一个完整的答案。

我知道了HashMap的数据结构,也知道了什么是Hash冲突,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。

对于第一个问题针对的是hashmap数组扩容时,新数组length = 原数组length * 2,沿用前面的例子(array.length = 2^4 = 16,二进制10000),array.length 乘以 2 ,即二进制左移一位,由 10000 变成 100000。此时需要重新计算数组槽中的元素位置,如果槽中是链表,链表中每个元素都需要重新计算位置(这里不考虑红黑树)。t同时,由于get时需要对链表其进行遍历,链表越长检索效率越差。那么,计算出的key值落点越平均,hash冲突的可能性越小。

key值的落脚点为key的hash值与数组长度作取余操作

,记作key.hashcode % array.length。



数学角度考虑,保持array.length为质数会使得计算结果更均衡,hashTable就是这么做的(数组初始值11)。但 hashmap 中 array.length 偏偏选择了2的次幂,是个合数.完全出于性能考虑!

结论:当 array.length长度是2的次幂时,key.hashcode % array.length等于key.hashcode & (array.length – 1)。

以长度为16 , key值为 10011011001 举例,也就是

array.length = 16 , 二进制为:10000

array.length – 1 = 15 , 二进制为 : 1111


key.hashcode % array.length

: 1001

key.hashcode & array.length-1 : 1001

计算过程:

​ 100 1101 1001

​ & 1111


​ 1001

发现两者计算的结果是一样的。

最终计算的结论就是:


10011011001 & ( 10000 - 1 ) = 10011011001 & 1111 = 1001 = 10011011001 % 10000

在这里插入图片描述

总结:

对hashmap而言,数组长度为2次幂有两点好处:

& 代替 %,可以提升性能

数组扩容时,仅仅关注 “特殊位” 就可以重新定位元素

仅关注 “特殊位” 就可以重新定位元素

性能,性能,还是性能……



版权声明:本文为qq_43663493原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。