简述 HashMap 扩容机制
HashMap基础
【注意】以下内容只是针对 JDK1.8
HashMap继承了AbstractMap类,实现了Map,Cloneable,Serializable接口。
其使用 hash 算法来决定元素的存储,hash 表包含如下属性。
- 容量(capacity):hash 表数组的大小,默认为16;
- 初始化容量(initial capacity):创建 hash 表时指定的初始容量;
- 尺寸(size):当前 hash 表中记录的数量;
- 负载(load):负载等于 “ size / capacity ”。负载为 0 时,表示空的 hash 表。轻负载的 hash 表具有冲突少、适宜插入和查询的特点。(但太小的话,又会增加占用的内存开销)。
- 负载因子(load factor):决定 hash 表的最大填满程度,范围是 0~1,默认为 0.75 。
当 hash 表的负载达到了指定的 “负载因子” 值时,hash 表就会加倍扩容,并将原有的对象重新分配,放入新的表中,这称为 rehashing 。rehashing 过程很复杂,而已非常消耗性能,所以指定一个合适的 “负载因子” 值很重要。
当 size / capacity > 负载因子,即 size(当前记录数) > 负载因子 * capacity(容量) 时,hash 会扩容。
HashMap的容量,默认是16
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
HashMap的加载因子,默认是0.75
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
当 HashMap 中元素个数超过 容量 * 加载因子 时,HashMap会进行扩容。即默认情况下,当 HashMap 中元素超过12个就会扩容
扩容多大?
HashMap 扩容是为当前容量 * 2,也就是成倍扩容。
【问题1】为什么每次扩容的倍数是2,而不是1.5或者2.5 ?
理论上,扩容倍数用多少都行,1.5, 2.5 ,3.5都可以的,都能实现HashMap。
实际上,HashMap选用了2倍,是为了做一个优化。
因为计算哈希值的时候是使用取模运算,而HashMap的开发者想要优化下这个取模运算的速度,那么他就需要把HashMap内部的数组长度固定为 2^n 的长度了,也就是说HashMap里面的数组的长度,始终都是2的n次幂。为了实现这个效果,它的扩容因子很自然就是2倍了。