还不懂HashMap的tableSizeFor()方法?看这篇就够了。
先上源码
/**
*这里要计算一个值,这个值要为2的n次方的值,要大于或等于cap(参数),并且最接近的。就比如30, 最接近的就是32.
**/
static final int tableSizeFor(int cap) {
int n = cap - 1;//这一步在后面说明,为啥-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;
}
算术符号说明:
1.n >>> 1(无符号右移): 二进制010,往右边移动一位变成001.【高位用0补充】
2. | (或): 1 | 0 为 1。
1.n |= n >>> x 说明
1.1算法推理说明
假如 n = 2^15+1 二进制为 0100000000000001, 那么计算tableSizeFor后的值为2^16 =1000000000000000 。(参数cap假设为2^15+2)
对比一下2^15+1 和 2^16 的二进制码
0100000000000001(2^15+1)
1000000000000000 (2^16)
对比说明:就是将2^15+1的最高位二进制位往左移一位, 后面的全部归零。
算法思路(重点): 将【2^15】0100000000000001 变成【0111111111111111】 ,然后再加1 就成了【2^16】1000000000000000。(这里是通过二进制的思维理解的)
1.2源码说明:
1. n |= n >>> 1 【分解为: n = n | (n>>>1)】 , n = 0100000000000001
0100000000000001( n )
0010000000000000(n>>>1 )
0110000000000000(n | (n>>>1) 最终结果)
简单的理解为:1 -> 变成了 11。其实就是将一个1 多复制了一个, 变成了 2个1 。
2. n |= n >>> 2
0110000000000000( n )
0001100000000000(n>>>2 )
0111100000000000(n | (n>>>2) 最终结果)
简单的理解为:11 -> 复制变成了 1111。
剩下怎么玩? 继续复制就完事了.
3. n |= n >>> 4
0111100000000000( n )
0000011110000000(n>>>4 : )
0111111110000000(最终结果)
简单的理解为:1111 -> 复制变成了 11111111。
4. n |= n >>> 8
0111111110000000( n )
0000000011111111(n>>>8 )
01111111111111111(最终结果)
最后变成了:0111111111111111。
5.还有最后一步 n |= n >>> 16;
0111111111111111 ( n )
00000000000000 (n>>>16 : 全是0,因为01111111111111111高位全是0, 太长了没写。)
01111111111111111(最终结果 )
最后将【2^15】0111111111111111 + 1 就会变成 1000000000000000【2^16】。
2.源码int n = cap - 1 说明
理解了上面的的思路的话,这一步就好理解了。
int n = cap - 1; //如果不这么做,按照上面的思路计算会导致得不到最接近的结果。
比如当cap = 32的时候,没有-1这个步骤,计算后的结果为64。
1.100000(32) 通过上面的步骤计算会变成 111111(63)
2.111111(63)+ 1 会变成100000 0( 64)。