原文标题:你所不知道的二进制实战技巧 Java实现
判断一个数是否是2的幂次方的方法
如果该数是无符号整数,可以使用
private static boolean isPowerOfTwo(int val) {
return (val & (val-1)) == 0;
}
如果一个数是2的n次方,那么这个数用二进制表示时其最高位为1,其余位为0,(val-1)和val都错开了0和1,那么&一定是0。
如果该数是无符号整数,也可以使用
private static boolean isPowerOfTwo(int val) {
return (val & -val) == val;
}
如果一个数是2的n次方,那么这个数用二进制表示时其最高位为1,其余位为0,(val & -val)就是获取最右1的位,那么如果和val等于就是了。
如何判断一个无符号数是2的n次方-1
private static boolean isPowerOfTwoLoseOne(int val) {
return (val & (val+1)) == 0;
}
理由其实和上面类似了
操作位代表类型
JDK SelectionKey有四种操作类型,分别为:
OP_READ = 1 << 0
OP_WRITE = 1 << 2
OP_CONNECT = 1 << 3
OP_ACCEPT = 1 << 4
由于只有四种网络操作类型,所以用4 bit就可以表示所有的网络操作位,由于JAVA语言没有bit类型,所以使用了整形来表示,每个操作位代表一种网络操作类型,分别为:0001、0010、0100、1000,这样做的好处是可以非常方便的通过位操作来进行网络操作位的状态判断和状态修改,提升操作性能。
说明:依稀记得RocketMQ里面好像也是类似,有一个当磁盘空间大于90%的时候不给写权限就是类似控制的,后续分析RocketMQ源码的时候会进行说明。
非2的幂次方转换为2的幂次方
在JDK很多集合框架里面,不知道你们还发现了,集合的大小都会是2的幂次方,哈哈,所以就引出了下面的话题。
int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
MAXIMUM_CAPACITY :
private static final int tableSizeFor(int c) {
int n = c - 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;
}
实例化ConcurrentHashMap时带参数时,会根据参数调整table的大小,确保table的大小总是2的幂次方,调用tableSizeFor的时候每次返回的都是大于等于离该数最近的2的幂次方的数。比如调用tableSizeFor传入c为151的时候 比151大的2的幂次方的数就是256了,核心就是上面的位运算操作。
刚刚上面是求一个数离它最近的大于等于2的幂次方的数,如果求小于等于2的幂次方的数,我们应该怎么办呢?
private static final int tableSizeFor(int n) {
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return n-(n>>1);
}
说明:由于集合的大小都会是2的幂次方,那么求table大小的0.75倍的时候,可以使用(n - (n >>> 2))即可,取模的时候,可以使用hash & 0x7FFFFFFF来进行操作即可。