Integer类有两个很有趣的方法,highestOneBit(int)和bitCount(int),前者是我指定HashMap初始化大小时寻找大于某个数的最小2的指数幂时候发现的,后者是看到leetcode上面一道算法题的时候,自己在Integer类中找到的解。下面上代码和分析过程。
(一)这是寻找最高位,我们使用 hightestOneBit(i) << 1就可以得到大于 i 的最小2的指数幂.
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);
}
我们以196作为寻找最高位的数,来一步步看过程。196只留最高位之后剩下的是2的7次方。
①当我们执行完方法的第一次运算之后,最高位的后一位必定是1,这样最高位与其下一位都是1.
②而执行完第二次运算之后,最高位及其后三位都是1
③这样执行完右移4、8、16位与之后,最高位之后的所有位都是1,再与自身右移相减就只保留最高位了。
(二)bitCount(i)是用来统计二进制数中1的个数,这也是leetcode上面的一道题。
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
我们这次以1995作为参考来看整个运算过程
①第一次运算,0x55555555是一个很特殊的数,他的奇数位全是1,偶数位全是0,第一次运算就是每两位记录下1的个数。
因为除了第一次运算,后面的运算都是加,如果第一次运算改成加也是一样的结果。
②0x33333333也是一个比较特殊的数,他是每4位数的前两位是0,后两位是1,第二次运算就是统计每4为中1的个数
③这样子后面的
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
都很容易理解了,就是统计每8位、16位、32位中1的个数,最后得到的数和63相与(因为int中1的个数不可能超过32,所以&63是取余),最后结果是8.
总结:Integer.hightestOneBit就是通过把最高位的1覆盖到后面的每一位,然后自身右移1位做差来保留最高位实现的。Integer.bitCount是通过计算每2位中1的个数、每4位中1的个数、每8位中1的个数、每16位中1的个数、每32位中1的个数来统计整个Integer中1的个数。