了解 HashMap 数据结构,超级详细!-4, 为什么 HashMap 数组的长度是 2 的幂次?
我们先看看它的成员变量:
序列化版本号
private static final long serialVersionUID = 362498820763181265L;
集合的初始化容量initCapacity
//默认的初始容量是16 -- 1<<4相当于1*2的4次方---1*16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
初始化容量默认是16,容量过大,遍历时会减慢速度,效率低;容量过小,那么扩容的次数变多,非常耗费性能。
负载因子
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
初始默认值为0.75,若过大,会导致哈希冲突的可能性更大;若过小,扩容的次数也会提高。
为什么必须是2的n次幂?
当向HashMap中添加一个元素的时候,需要根据key的hash值,去确定其在数组中的具体位置。HashMap为了提高存取效率,要尽量较少碰撞,就是要尽量把数据分配均匀,每个链表长度大致相同,这个实现就在把数据存到哪个链表中的算法。
这个算法实际就是取模,hash%length,计算机中直接求余效率不如位移运算。所以源码中做了优化,使用 hash&(length-1)
,而实际上hash%length
等于hash&(length-1)
的前提是length是2的n次幂。
如果输入值不是2的幂会怎么样?
如果数组长度不是2的n次幂,计算出的索引特别容易相同,及其容易发生hash碰撞,导致其余数组空间很大程度上并没有存储数据,链表或者红黑树过长,效率降低。
小结:
1,当根据key的hash确定其在数组的位置时,如果n为2的幂次方,可以保证数据的均匀插入,如果n不是2的幂次方,可能数组的一些位置永远不会插入数据,浪费数组的空间,加大hash冲突。
2,一般可能会想通过 % 求余来确定位置,这样也可以,只不过性能不如 & 运算。而且当n是2的幂次方时:hash & (length - 1) == hash % length
3,因此,HashMap 容量为2次幂的原因,就是为了数据的的均匀分布,减少hash冲突,毕竟hash冲突越大,代表数组中一个链的长度越大,这样的话会降低hashmap的性能
好了,今天就先分享到这里了,下期继续给大家带来HashMap面试内容!更多干货、优质文章,欢迎关注我的原创技术公众号~
上一篇: 如何快速查看 idea 中的所有断点