-
public HashMap()
/**
* Constructs an empty <tt>HashMap</tt> with the default initial capacity
* (16) and the default load factor (0.75).
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
可以看到, 如果调用不带参数的构造方法, HashMap将会初始化一个默认的负载因子, 值为0.75, 这个负载因子是表示Map空间填满程度, 当Map存储的元素达到阀值, 则会自动扩容.
-
public HashMap(int initialCapacity)
/**
* Constructs an empty <tt>HashMap</tt> with the specified initial
* capacity and the default load factor (0.75).
*
* @param initialCapacity the initial capacity.
* @throws IllegalArgumentException if the initial capacity is negative.
*/
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
注释已经写得很清楚了, 使用指定的初始容量和默认负载因子(0.75)构造一个空的 HashMap, 将参数和默认的负载因子传入另一个构造方法, 我们直接来看这个 this 指向的另一个构造方法.
-
public HashMap(int initialCapacity, float loadFactor)
/**
* Constructs an empty <tt>HashMap</tt> with the specified initial
* capacity and load factor.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
首先不允许你将Map的初始容量设为负数, 否则直接抛异常了. 然后判断初始容量是否大于最大可设置容量, 如果大于则直接用最大可设置容量覆盖掉传进来的初始容量, 再去判断负载因子是否符合条件, 不符合则抛出异常.
如果都没问题, 则将负载因子赋值, 然后调用 static final int tableSizeFor(int cap) 方法.
/**
* Returns a power of two size for the given target capacity.
*/
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
这方法什么意思呢, 就是为了算出大于等于 initialCapacity 的最小的2的幂, 然后将值赋给 threshold 变量. 而这个 threshold 正是用来判断Map是否需要扩容的
开始的时候会觉得下面这段代码是错的
this.threshold = tableSizeFor(initialCapacity);
threshold 不应该是直接赋值的, 我们知道, 当Map中的元素个数大于(Map的容量 * 负载因子)时, Map才应该扩容, 所以, 触发Map扩容的阀值应该是如下代码
this.threshold = tableSizeFor(initialCapacity) * this.loadFactor;
但是,请注意,在构造方法中,并没有对table这个成员变量进行初始化,table的初始化被推迟到了put方法中,在put方法中会对threshold重新计算,具体解读, 在下节见分晓.