先看一下原函数的注释
/**
* Initializes or doubles table size. If null, allocates in
* accord with initial capacity target held in field threshold.
* Otherwise, because we are using power-of-two expansion, the
* elements from each bin must either stay at same index, or move
* with a power of two offset in the new table.
*
* @return the table
*/
使用场景
Initializes or doubles table size.
resize 规律
原来某个坑位中的元素,要么还留在原来的位置,要么移动 a power of two 个位置。实际上是移动原来数组长度个位置。
整体流程
- newTab = new 一个二倍原长度的 Node 数组,threshold 变成两倍;
- 将 table (Map中存放元素的容器)指向 newTab;
- 依次遍历原来 Node 数组的每个坑位,将坑中的元素进行 rehash。
一个 table length 从 8 到 16 的 扩容例子
当然实际数组初始长度最小为 16, 不存在从 8 到 16 的扩容,只是为了好画图。
假设元素的 hash(key) = key
Node 节点中存储的 hash 其实就是 key 的 hash 值
亦即:(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)
Node 节点定义:
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
// otherThings
}
0. 初始状态
一个长度为 8 的数组,loadfactor = 0.75,threshold = 6.
/**
* The next size value at which to resize (capacity * load factor).
*
* @serial
*/
int threshold;
1. 建立新table
resize() 函数会在两种情况下被调用:
- HashMap new 出来后还没有 put 元素进去,没有真正分配存储空间被初始化,调用 resize() 函数进行初始化;
- 原 table 中的元素个数达到了
capacity * loadFactor
这个上限,需要扩容。此时调用 resize(),new 一个两倍长度的新 Node 数组,进行rehash,并将容器指针(table)指向新数组。
final Node