ConcurrentHashMap之tableSizeFor()方法透析(位运算运用)

  ConcurrentHashMap和HashMap有如下方法
inttableSizeFor(int c)
//功能:输入低于最大容量的数c,返回大于等于且最接近c的2的幂次数。 源码:  
private static final int MAXIMUM_CAPACITY = 1 << 30;
 
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;
}

 

解释/总结1:符号>>:右移n位相当于除以2的n次方。符号<<:左移n位就相当于乘以2的n次方。 >>>无符号右移:"零扩展",无论正负,左边都补0。|符号,按位或,使用二进制计算:0|1=1,0|0=0,1|1=1 2:设c=010001101,即141. 执行:先减1,n=140--转为2进制---010001100       n |= n >>> 1------无符号右移一位,左边补0     001000110 |       |操作     010001100    ->n=011001110     n |= n >>> 2------同上     011001110 |      000110011      ->n=011111111=255 最高位1后面已经均为1,后面再执行|操作n不会发生变化了, 最后n=255,返回n+1即256。可以看出该算法通过几次无符号右移和|操作会让最高位的1后面的位全变为1。 3:在使用位运算之前减1是必要的,否则对于c=16,最后就会得到32.实际需求应当返回16. 4:为什么最后写到n|n >>> 16?我们知道int范围在-2^31~2^31-1,因此对于int最大的2次幂数为2^30,这也就是MAXIMUM_CAPACITY的值。c超过这个值就会返回MAXIMUM_CAPACITY。 而这边代码中一共右移了1+2+4+8+16=31位,因此可以保证高位1以下的低位都会变成1. 5:如果c是负数,那么结果如何
int c=-100;
c|= c >>> 1;
System.out.println( c );
c|= c >>> 2;
System.out.println( c );
c|= c >>> 4;
System.out.println( c );
c|= c >>> 8;
System.out.println( c );
结果:
-34
-1
-1
-1

 

运算过程中|操作后使用补码运算同样会不断的将0变成1;最后就会变成111111111111111111...=-1   实践发现如果传入负数最后n最大会变成-1,而上述算法中(n < 0) ? 1会返回1,不会有异常.
  6:总结:这个算法主要是对位运算的运用.这里我总结一下位运算的运用  |按位或运算:可以将指定的低位从0变成1,如a|0111 (2进制),这样就可以将低3位 置为1.  ^异或运算:这个运算是相同的位得0,不同的得1. 它可以用来反转低位得值.如 1001^0111(2进制) =1110,后三位反转了.还有之前学过的可以用来交换a,b: a=a^b;b=b^a;a=a^b; &按位与操作:可以用来保留后n位:如:010101&0111=000101这样保留后三位不变,其余为0. <<左移:左移n等同于乘以2的n次方 >>右移:右移n等同于除以2的n次方,正数右移高位补0,负数右移高位补1 >>>无符号右移:无论是正数还是负数,高位都补0。 (左移右移时需要注意范围)   应用: //判断两个int类型数是否同正负: //只要看高位的数是不是不同即可
public static boolean SameSymbolInt(int a,int b){
    return ((a >> 31) ^ (b >> 31)) == 0;
}

 

上一篇:PAT 1007 Maximum Subsequence Sum 最⼤连续⼦序列和


下一篇:LeetCode-718. Maximum Length of Repeated Subarray