说位移运算之前,先补下二进制
二进制
符号位
用二进制表示有符号整数,最高位作为符号位0正1负
以int(32位)为例,则
- 最大值为
0111 1111 1111 1111 1111 1111 1111 1111
即-1,即Integer.MAX_VALUE,即2147483647 - 最小值为
1000 0000 0000 0000 0000 0000 0000 0000
即-, 即Integer.MIN_VALUE,即-2147483648
正负数
正数的二进制平平无奇,负数却并非正数二进制简单的符号位0换1获得,而是通过二进制补码来表示,即负数二进制补码 = 正数二进制取反码 + 1
如-5二进制:
5的二进制表示: 0000 0000 0000 0000 0000 0000 0000 0101
取反得到反码: 1111 1111 1111 1111 1111 1111 1111 1010
反码加1得补码: 1111 1111 1111 1111 1111 1111 1111 1011
左移运算符 <<
将原二进制数值向左移指定位数,右边补0
如 5 << 2:
5的二进制: 0000 0000 0000 0000 0000 0000 0000 0101
左移2位即: 0000 0000 0000 0000 0000 0000 0001 0100 ,即20
所以 5 << 2 = 5 * = 20
所以x左移n位,即: x << n = x * ,此计算方式在结果小于Inetger.Max_VALUE时适用
那么 5左移32位会怎么样呢?为了便于理解,我们用1左移32位来解释这个问题
1的二进制: 0000 0000 0000 0000 0000 0000 0000 0001
左移30位: 0100 0000 0000 0000 0000 0000 0000 0000 -->没问题
左移31位: 1000 0000 0000 0000 0000 0000 0000 0000 -->符号位被覆盖,此时值为-2147483648
左移32位: 0000 0000 0000 0000 0000 0000 0000 0001 -->循环移位,此时值为1
左移33位: 0100 0000 0000 0000 0000 0000 0000 0010 -->循环移位,此时值为2
左移34位: 0100 0000 0000 0000 0000 0000 0000 0100 -->循环移位,此时值为4
...
左移63位: 0100 0000 0000 0000 0000 0000 0000 0100 -->符号位被覆盖,此时值为-2147483648
左移64位: 0000 0000 0000 0000 0000 0000 0000 0001 -->循环移位,此时值为1
右移运算符 >>
将原二进制数值向右移指定位数,正数左边补0,负数左边补1
如 5 >> 2:
5的二进制: 0000 0000 0000 0000 0000 0000 0000 0101
右移2位: 0000 0000 0000 0000 0000 0000 0000 0001 -->即1
右移3位: 0000 0000 0000 0000 0000 0000 0000 0000 -->即0
右移4位: 0000 0000 0000 0000 0000 0000 0000 0000 -->即0
如上所示,正数无论右移多少位,都不会得到负数
所以x右移n位,即: x >> n = x / 向下取整
如 -5 >> 2:
-5的二进制: 1111 1111 1111 1111 1111 1111 1111 1011
右移2位: 1111 1111 1111 1111 1111 1111 1111 1110 -->即-2
右移3位: 1111 1111 1111 1111 1111 1111 1111 1111 -->即-1
右移4位: 1111 1111 1111 1111 1111 1111 1111 1111 -->即-1
如上所示,负数无论右移的到的最大值为-1 同样x右移n位,即: x >> n = x / 向下取整
无符号右移运算符 >>>
将原二进制数值向右移指定位数,无论正负,左边都补0
如 -5 >>> 2:
-5的二进制: 1111 1111 1111 1111 1111 1111 1111 1011
右移2位: 0011 1111 1111 1111 1111 1111 1111 1110 -->即1073741822
有无符号左移运算吗? 无符号左移即【将原二进制数值向左移指定位数右边补0】,其实就是左移运算了
与 &
对应位都为 1 时,结果为 1;否则为 0
int a = 5; // 0101
int b = 3; // 0011
int result = a & b; // 0001 -> 1
或 |
对应位只要有一个为 1,结果为 1;否则为 0
int a = 5; // 0101
int b = 3; // 0011
int result = a | b; // 0111 -> 7
取反 ~
对应位 0 变为 1,1 变为 0
int a = 5; // 0000 0000 0000 0000 0000 0000 0000 0101
int result = ~a; // 1111 1111 1111 1111 1111 1111 1111 1010 -> -6
异或 ^
对应位不同则为 1,相同则为 0
int a = 5; // 0101
int b = 3; // 0011
int result = a ^ b; // 0110 -> 6
一个实例
通过位运算简便的作标记
int a = 0x01; //1
int b = a << 2; //4
int c = a << 7; //128
int d = a << 8; //256
int valueABC = a | b | c; //133
int valueAC = a | c; //129
System.out.println("valueABC是否包含c:" + ((valueABC & c) == c)); //true
System.out.println("valueABC是否包含d:" + ((valueABC & d) == d)); //false
System.out.println("valueABC去掉b:" + (valueABC & ~b)); //129,即a|c