声明:以下对源码解读,是本人个人理解,水平有限,如有错误,请及时告诉我!
在创建HashMap对象,并在构造器传入初始化容量的时候,会调用tableSizeFor方法,返回 >=初始化对象最近的2的倍数。
阅读前需要了解的知识(以下为快速理解,如需详情百度)
如果已了解位移和位运算,请跳过
>>>(无符号右移):整体二进制数字向右移动,移动后,高位补0,末尾舍去 例:55(二进制110111) >>> 1 = 27(二进制11011)
55(二进制110111) >>> 2 = 13(二进制1101)
>>> 后面的数字代表位移几位
|(按位或运算):两个数字的二进制做运算,两边的每一位数字做 | 运算,有1则为1(同类似条件或 | 运算,有true则为true)一个道理,把二进制0看作false,1作ture,进行按位或运算,得到一个新数字(我估计我可能文字说不明白,看例子)。
0 | 0 = 0, 0 | 1 = 1, 1 | 0 = 1, 1 | 1 = 1 【把0当作false,1当作true,好记,好理解】
例子:110111(十进制55)| 11011(十进制27)
11011(十进制27) 我的图是 011011,高位补0
2的倍数在二进制当中,都是1000…后面全是0。
2(10)4(100)8(1000)16(10000)
那么得到一个数,>=他的2的倍数,只有这个数的二进制全变为 111…然后+1即可
1(1)3(11)7(111)15(1111)
上面的数字 +1 即变为了2的倍数
源码
/**
* Returns a power of two size for the given target capacity.
*/
// 传入的初始化容量
static final int tableSizeFor(int cap) {
//初始化容量 - 1。保证cap本身是2的倍数,返回也是cap。
//例如:cap = 32 ,返回 32。如没有-1,cap = 32 返回 64
int n = cap - 1;
//按位或,无符号右移 n = n | (n >>> 1,2,4,8,16)
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
// 到这里n的二进制应该是 111...若干的1
// 最后的 n + 1及为变成2的倍(可不是为了补上的n-1,没有直接关系)
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
上面代码中,最主要就是,n |= (n >>> 1,2,4,8,16)
例:还是以55(110111)举例
n | = n >>> 1
java中int占4个字节,也就是有32位,符号位在最高位,0为整数,1为负数
后面的以此类推,1 + 2 + 4 + 8 + 16 = 63 除了整数位,正好其他的位数都能为 1111… 并且1,2,4,8,16都为前一个数的倍数,正好可以把前一次位移运算的的1,当作下次的进行运算。 然后在最后的三元哪里 n+1及变为了2的倍数。
(上述的源码注释有写道,如果cap正好的2的倍数,如果没有-1)
例:8(1000)
转后
15(1111)
三元n+1
16(10000)
最后感叹一下,还是要多学习,才能感受到自己是个井底之蛙,万不可死于安乐。