关于HashMap初始化容量问题

基于阿里代码规范HashMap 需要初始化大小问题了解了一波

关于jdk内描述

HashMap的实例有两个参数影响其性能:初始容量和加载因子。

首先我们来看初始容量和加载因子的定义。

容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。

加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。

当哈希表中条目的数目超过 容量乘加载因子 的时候,则要对该哈希表进行rehash操作,从而哈希表将具有大约两倍的桶数。

当我们往hashmap中put元素的时候,先根据key的hash值得到这个元素在数组中的位置(即下标),然后就可以把这个元素放到对应的位置中了。如果这个元素所在的位子上已经存放有其他元素了,那么在同一个位子上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。从hashmap中get元素时,首先计算key的hashcode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。如果每个位置上的链表只有一个元素,那么hashmap的get效率将是最高的。

HashMap为元素选择下标的方法

length为数组长度,h为key获取到的hashcode
1
2
3
static int indexFor(int h, int length) {  
return h & (length-1);
}

当数组长度为2的n次幂的时候,不同的key算得得index相同的几率较小,那么数据在数组上分布就比较均匀,也就是说碰撞的几率小,相对的,查询的时候就不用遍历某个位置上的链表,这样查询效率也就较高了。

所以,在存储大容量数据的时候,最好预先指定hashmap的size为2的整数次幂次方。就算不指定的话,也会以大于且最接近指定值大小的2次幂来初始化的,代码如下(HashMap的构造方法中):

1
2
3
4
// Find a power of 2 >= initialCapacity  
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;

关于HashMap的rehash

当元素个数超过数组长度*加载因子时,HashMap将发生扩容,使其提高查询效率,但当其扩容后,原数组中的数据必须重新计算其在新数组中的位置,并放进去,这是一个导致消耗性能的操作,所以如果我们已经预知hashmap中元素的个数,那么预设元素的个数能够有效的提高hashmap的性能。比如说,我们有100个元素,100/0.75 = 133.33。为了防止rehash,向上取整,为134 但是new HashMap(134)显然不符合数组长度为2的n次幂的时候效率更高, 我们必须这样new HashMap(256)才最合适,既考虑了&的问题,也避免了rehash的问题。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!