无参数构造器的初始容量和负载因子为16,0.75.
其他传入指定容量的构造器会根据传入的构造器设置容量为2^n 》=(容量),n取最小值。
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;
}
这个方法的作用是取到最小》=cap的2^n值
cap一定大于0,那么只要把最高位到末尾位全部变成1,然后加上1,就可以得到我们需要的值。
比如5,0000 0101 (1)-----》 0000 0111 (2)------> 0000 1000
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
这块代码,就是负责把最高位到末尾位全部变成1。
先来一个简单的例子。根据公式 a|=b ----> a = a | b
比如:a = 2 | (2>>>1)
所以要从1开始,依次以2的倍数递增。1+2+4+8+16=31,可以把任意的int型变量,取到最小的那个2^n值,为了防止int溢出,jdk做了如下处理
static final int MAXIMUM_CAPACITY = 1 << 30; 2^30
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);
MAXIMUM_CAPACITY 这个值设计的很巧妙,恰好和tableSizeFor中的算法相辅,使得int不会溢出。因为int位数有32位,减去一位符号位,还有31位,方法的参数大于MAXIMUM_CAPACITY的值的都会被替换成MAXIMUM_CAPACITY,移位之后的阈值不会超过31位的范围。
static final int tableSizeFor(int cap) {
int n = cap - 1;
}
减一原因:
防止cap本身就是2^n,从而导致分配了多一倍的空间。