构造函数
从构造函数开始说起
public HashMap(int initialCapacity, float loadFactor) {
//如果指定的初始容量小于0
if (initialCapacity < 0)
//非法参数异常
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
//如果大于初始容量 默认为最大初始容量
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
//如果装填因子小于0 或者 不是一个数
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
//赋值
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
threshold是什么??
threshold 要调整大小的下一个大小值(容量*加载因子)。 来自官方API的解释
要调整的下一个 下一个的意思 是 返回2的n次幂表示的数 如果cap为10 则 结果为16
以下是tableSizeFor的源码
/**
* Returns a power of two size for the given target capacity.
* 返回扩容后的长度 默认是最接近cap的向上取整 2的n次幂表示的数 如果cap为10 则 结果为16
*/
//这个函数的作用是 返回 下一个2的n次幂表示的数
//2的n次幂是怎么表示的 2 4 8 16
//他们都可以表示为 1+1 3+1 7+1 15+1
//注意这些奇数的二进制都可以表示为 1 11 111 1111
//那么以下代码就好理解了 就是 逐步将cap变为 下一个 全是1的二进制数
//换句话说整个代码 就是消灭 n中的0 使其变为1
// cap=10 n=9
static final int tableSizeFor(int cap) {
int n = cap - 1;
//|= 优先级是最低的
//
n |= n >>> 1;
//先计算n右移一位再或运算 n |= 9>>>1
// 0000 1001
// 0000 0100
// 0000 1101
;
// 0000 1101
// 0000 0011
// 0000 1111
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
总结 对于 任何 正数n的二进制表达式
n|= n >>> 1
必定使一个相邻的10 变为11 那么再下一次的运算只需
n |= n >>> 2 因为n的二进制中至少会有两个连续的11
理想情况下 这将至少产生 四个连续的1111
所以下次 只需右移动4位
可以对二进制 1000 0000 进行上述位运算 一切就明白了
什么是装填因子
装填因子(load factor)
装填因子(load factor)决定何时对散列表进行再散列
如果装填因子默认为0.75 并且表中超过75%的位置已经填入元素
也就是说 如果表的长度是16当添加第16*0.75+1个元素时 也就是表中元素的个数到达临界值时 表将会进行resize()操作 这个表就会用双倍额的桶数自动地再进行散列
这里的双倍是自动转换为下一个二次幂函数的数