今天在学习JDK7 HashMap源码时,它在创建数组容量大小的时候用到了Integer.highestOneBit方法
HashMap中的源码
private static int roundUpToPowerOf2(int number) {
// assert number >= 0 : "number must be non-negative";
return number >= MAXIMUM_CAPACITY
? MAXIMUM_CAPACITY
: (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;
}
Integer中的 highestOnBit方法源码
public static int highestOneBit(int i) {
// HD, Figure 3-1
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
}
刚看到这个代码,我直接黑人问号!后来老师和网上资料的学习有了一点眉目。
JDK注释
* Returns an {@code int} value with at most a single one-bit, in the * position of the highest-order ("leftmost") one-bit in the specified * {@code int} value. Returns zero if the specified value has no * one-bits in its two's complement binary representation, that is, if it * is equal to zero. * * @return an {@code int} value with a single one-bit, in the position * of the highest-order one-bit in the specified value, or zero if * the specified value is itself equal to zero. * @since 1.5
额,再次黑人问号,用翻译插件翻译文本如下
返回具有至多单个 1 位的 int 值,在指定的 int 值中最高位(最左边)的 1 位的位置。如果指定的值在其二进制补码表示形式中不具有 1 位,即它等于零,则返回零。
在用通俗易懂的话来说就是:
- 如果一个数是0, 则返回0;
- 如果是负数, 则返回 -2147483648:【1000,0000,0000,0000,0000,0000,0000,0000】(二进制表示的数);
- 如果是正数, 返回的小于等于这个数的2的N次方
例如:举几个例子
public static void main(String[] args) {
System.out.println(Integer.highestOneBit(0)); // 0
System.out.println(Integer.highestOneBit(16)); //16
System.out.println(Integer.highestOneBit(15)); //8
System.out.println(Integer.highestOneBit(-1)); //-2147483648 = Integer.MIN_VALUE
}
按照代码的逻辑思路,我们一步一步来解读解读,例如数字 17
int 占 4个字节,32位, 17的二进制数为: 0000 0000 0000 0000 0000 0000 0001 0001,因为前面都是重复的 0 我们只用 后八位来做演示 0001 0001
17 0001 0001
>>1 0000 1000
| 0001 1001
>>2 0000 0110
| 0001 1111
>>4 0000 0001
| 0001 1111
>>8 0000 0000
| 0001 1111
>>16 0000 0000
| 0001 1111
//i - (i >> 1)
0001 1111
0000 1111
= 0001 0000 // 16 的二进制位
看到这里可能看出来点门道,我们则可以测试把最高位以后的位都用星号表示
17 0001 ****
>>1 0000 1***
| 0001 1***
>>2 0000 011*
| 0001 111*
>>4 0000 0001
| 0001 1111
>>8 0000 0000
| 0001 1111
>>16 0000 0000
| 0001 1111
//i - (i >> 1)
0001 1111
0000 1111
= 0001 0000 // 16 的二进制位
这个运算的过程无非就是将该数字对应的二进制数中除最高位的1之外的其他bit位都清零,则拿到了我们想要的结果。
右移与或运算的目的就是想让某个数字的低位都变为1,再用该结果 减去 该结果右移一位后的结果,则相当于清零了原数字的低位。即得到了我们想要的结果。
补充:1、为什么是右移 1 2 4 8 16 而不是其他的数呢?
1 + 2 + 4 + 8 + 16 = 31, 2的31次方,直到把原来最高位变成0所以要这么多次
补充:1、为什么是在HashMap源码调用时要先-1?
例如:如果数字为16,不 -1,在运算后得到的还会是16,计算出的opacity = 32 ;违背了hash容量计算——大于等于该数的2次方幂。