在读HashMap源码是遇到了highestOneBit这个方法,不懂,看了一下源码。
Integer.highestOneBit(i)
这个方法的作用就是取i对应二进制值最左边最高位,其余后面全部补零,并返回对应int类型的值。
highestOneBit方法源码如下:
/**
* 将一个整数(二进制)设置最高位为1,其它位为0,然后返回改变后的值
* 如果这个整数是0返回0
* @param i
* @return
*/
public static int highestOneBit(int i) {
// 例如1000
i |= (i >> 1); // 使前2位变为1,相当于i = i | (i >> 1); i = 1000 | 0100 = 1100
i |= (i >> 2); // 使前4位变为1,由于上一步确保了前两位都是1,所以这一次移动两位,1111
i |= (i >> 4); // 使前8位变为1,1111
i |= (i >> 8); // 使前16位变为1,1111
i |= (i >> 16); // 使前32位变为1,1111
return i - (i >>> 1); // i >>> 1 无符号右移,使最高位为0,其余位为1,相减即得出结果,1111 - 0111 = 1000
}
要理解
上述源码需要一部分二进制的基础,可以去看我的另外一篇文章,JAVA二进制基础
我们都知道32位的int值取值范围为-2的32次幂到(2的32次幂-1),这是为啥呢?
因为二进制的最高位为符号位,0表示正数,1表示负数,那么毋庸置疑,
32位最大值的二进制形式为:
0111 1111 1111 1111 1111 1111 1111 1111 转化为int类型就是2的32次幂-1
因为最高位是符号位,负数为1,所以32位的最小值的二进制形式为:
1111 1111 1111 1111 1111 1111 1111 1111
我们知道二进制负数的值是用他对应正值的反码加1来获得,那么可以反向推出他的十进制值
负数源码: 1111 1111 1111 1111 1111 1111 1111 1111
原码减一获得反码: 0111 1111 1111 1111 1111 1111 1111 1111反码取反获得负数对应正值 : 1000 0000 0000 0000 0000 0000 0000 0000 2的32次幂
所以1111 1111 1111 1111 1111 1111 1111 1111 转化为十进制就是 负的2的32次幂。
下面再来解释,为啥方法中右移了这么多次:
因为32位的int值最终有32位,所以他总共右移了32位,最终使前32位变为1,然后在进行无符号位右移,用原值减去无符号位右移的值就得到了最高位1其余为0的二进制