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; }