最近在看hashmap的源码,看到一个很有意思的函数,tableSizeFor,不禁想问,这个函数到底做了什么?
static final int tableSizeFor(int var0) {
int var1 = var0 - 1;
var1 |= var1 >>> 1;
var1 |= var1 >>> 2;
var1 |= var1 >>> 4;
var1 |= var1 >>> 8;
var1 |= var1 >>> 16;
return var1 < 0 ? 1 : (var1 >= 1073741824 ? 1073741824 : var1 + 1);
}
我们先把函数源码摆上来,里面出现了几个关键的java运算符
\>>>:按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。
| :如果相对应位都是 0,则结果为 0,否则为 1。
清楚了运算符的作用,我们举例来说明:
var0为7
7的二进制: 0000 0111
var0-1=6 : 0000 0110
var1>>>1 : 0000 0011
var1 |= var1 >>> 1 : 0000 0110
var1 |= var1 >>> 2 : 0000 0111
后续操作结果一样
var1+1 = 8
从这个例子中,我们得出一个结论,这个函数做了以下操作:将原操作数-1,然后将二进制的第一个1之后的所有数变为1,最后返回,操作数+1
那这到底完成了什么功能呢?从上面的分析来看,是为了找出大于等于本身的值的最近的一个2的幂次方值,那为什么刚开始要减去一个1呢?稍等,我们通过另外一个例子说明一下
cap 8
0000 10000000 0100 n>>>1
0000 1100 n|n>>>1
0000 0011 n>>>20000 1100
0000 1111 n|n>>>2 低位全为1,后续操作结果一样
0000 0001 n+1
0001 0000 16
cap = 15 + 1 = 16
从这个例子上看到,如果原先操作数本身就是2的幂次方,不减去1,直接进行后续操作,那么最后+1之后,肯定会得到大于本身值的下一个2的幂次方。
总结
说到这里,其实大家已经看明白了,这个函数的作用就是为了找出大于等于每个输入值的,最接近的2的幂次方值。不得不说,JDK这里的这个小算法,还是设计挺巧妙的。