1左移、右移、无符号右移
左移(<<):运算符左边的对象向左移动运算符右边指定的位数(在低位补0)
右移(>>):运算符左边的对象向右移动运算符右边指定的位数。使用符号扩展机制(如果值为正,则在高位补0,如果值为负,则在高位补1)
无符号右移(>>>):运算符左边的对象向右移动运算符右边指定的位数。采用0扩展机制(无论值的正负,都在高位补0)
注:x<<y 相当于 x*2y ;x>>y相当于x/2y
从计算速度上讲,移位运算要比算术运算快。
如果x是负数,那么x>>>3没有什么算术意义,只有逻辑意义。(计算机是补码的形式存储)
与按位运算符一样,移位运算符可以用于byte、short、int、long等整数类型,和字符串类型char,但是不能用于浮点数类型float、double;当然,在Java5.0及以上版本中,移位运算符还可用于byte、short、int、long、char对应的包装器类。
2有趣的问题
对一个int型的数字a,a>>32 = a<<32 = a。
例如,整数1(0000 0000 0000 0001),按照上述规则1<<32 = 0(0000 0000 0000 0000),左移低位补0。而实际结果却是1.
Think in Java给出了解释:
“对char,byte或者short进行移位处理,那么在移位进行之前,它们会自动转换成一个int。只有右侧的5个低位才会有用。这样可防止我们在一个int数里移动不切实际的位数。若对一个long值进行处理,最后得到的结果也是long。此时只会用到右侧的6个低位,防止移动超过long值里现成的位数。”
说白了就是移多了没什么意义。这里5个低位[00000,11111]。所以以上几个类型只有在[0,31]范围位移才有效。那么若位移数大于31会怎么样呢?
jdk是这么做的:采用模运算。所以1<<32 = 1<<(32%32)= 1<<0 = 1。
3位移运算在hashMap源码中的经典应用
static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); }
之前看源码的时候一直不明白为什么要这么做。下面大家看一个例子可能就猜出来了(结合hashMap设计原则)
public class Test { public static void main(String[] args) { Integer number1 = 80000; printInfo(number1.hashCode()); printInfo(hash(number1.hashCode())); Integer number2 = 1024; printInfo(number2.hashCode()); printInfo(hash(number2.hashCode())); } // 输出一个int的二进制数 private static void printInfo(int num){ System.out.println(Integer.toBinaryString(num)); } static int hash(int h) { h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4); } }
输出:
10011100010000000
10010100101101011
10000000000
10001001000
hashMap采用数组和链表实现,设计当然希望这个HashMap里面的 元素位置尽量的分布均匀些,尽量使得每个位置上的元素数量只有一个,那么当我们用hash算法求得这个位置的时候,马上就可以知道对应位置的元素就是我们要的,而不用再去遍历链表,这样就大大优化了查询的效率。而原始数据经过hash方法后,1的分布更加均匀。有没有想到点什么?不得不佩服设计这段代码的大神~