在HashMap的tableSizeFor方法中这段代码很有意思
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;
}
首先需要知道这个代码是干嘛的:
他的意义就是找到比输入大的,并且与输入相邻的2的次方数。
比如输入3,输出4。输入5、6、7,输出8。
然后,什么是|。
就是二进制运算时,有1就是1。
1|0=1,1|1=1,0|0=0。
右移几位。直接往右移就完了,0补位,很简单。
111>>>1=011。
111>>>2=001。
右移几位。直接往右移就完了,0补位,很简单。
111>>>1=011。
111>>>2=001。
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
下面开始计算。以输入10为例。你也可以随便选择一个数,按照下面步骤进行。
比如输入10,10-1=9,9化成二进制就是:1001。
然后开始这步:
n |= n >>> 1;
此时n=1001,n先右移1位,变成0100。
然后0100再与之前的n做或运算,也就是0100|1001=1101。
此时n=1101。
然后是:
n |= n >>> 2;
1101>>>2=0011
0011|1101=1111
此时n=1111。
然后是:
n |= n >>> 4;
聪明的人已经知道了,以后的结果都是1111,不信给你算。
1111>>>4=0000
0000|1111=1111
此时n=1111。
然后是
n |= n >>> 8;
1111>>>8=0000 0000
0000 0000|1111也就是0000 0000|0000 1111 = 0000 1111
0000 1111也就是1111。
此时n=1111。
移16就不用算了,你得多笨。
这时候发现了啊,一直右移,做或运算,最后就变成了全是1的。然后再看tableSizeFor的代码最后一行,最后要得到n+1。
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
这段代码先是判断n是否小于0,这个防御判断就不用管了。大于0的时候,判断n和MAXIMUM_CAPACITY的大小,取值MAXIMUM_CAPACITY或者n+1。
这里可以这么理解:
n >= MAXIMUM_CAPACITY 可以写成n + 1 > MAXIMUM_CAPACITY
也就是:
(n + 1 > MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
然后就理解成,n+1和MAXIMUM_CAPACITY谁大就取谁。
我们输入的10,最后得出1111,1111+1之后是几?是10000,16,也就是2的4次方。
也就是处理完之后,必然是全1,也就是2的幂-1,那么返回n+1;
int n = cap - 1;
这一步是为了防止传入的cap本来就是2的幂,结果处理成2n+1了。