最近看 JDK 的源码, 看到一些 按位运算(Bitwise Operators), 这里做个总结.
1 按位运算符汇总
Operator | Description |
---|---|
& | Bitwise AND(按位与) |
| | Bitwise OR(按位或) |
^ | Bitwise XOR(eXclusive OR, 按位异或) |
~ | Bitwise Complement(按位取反) |
<< | Left Shift(左移) |
>> | Signed Right Shift(有符号右移) |
>>> | Unsigned Right Shift(无符号右移) |
备注:
有符号右移: 右移时不移的符号位.
无符号右移: 右移时移动符号位. (可以理解为 把符号位当做普通的二进制位)
对于正数来说, 有符号右移 和 无符号右移 没有区别, 因为在右移完事了, 左边都要用 0 补齐.
左移: 也会 把符号位当做普通的二进制位.
优先级:
运算符 | 综合性 |
---|---|
~ | 从右向左 |
<< >> >>> | 从左向右 |
& | 从左向右 |
^ | 从左向右 |
| | 从左向右 |
=(赋值运算符) | 从右向左 |
2 按位与 &
按位与, 两位都为1结果才为1(全1则1):
x | y | x&y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
例如:
3 & 5
结果为 1
.
(decimal) (binary)
3 = 011
5 = 101
------------------ 按位与(&)
1 = 001
3 按位或 |
按位或, 有1位为1结果就为1(有1则1):
x | y | x|y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
例如:
3 | 5
结果为 7
.
(decimal) (binary)
3 = 011
5 = 101
------------------ 按位或(|)
7 = 111
4 异或 ^
异或, 两位不同则为1(相异为1):
x | y | x^y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
例如:
3 ^ 5
结果为 6
.
(decimal) (binary)
3 = 011
5 = 101
------------------ 异或(^)
6 = 110
5 按位取反 ~
按位取反:
x | ~x |
---|---|
0 | 1 |
1 | 0 |
例如:
~3
结果为 -4
.
(decimal) (binary)
3 = 011
------------------ 按位取反(~)
-4 = 100
特别注意:
按位取反 ~
会改变符号位.
备注:
Java 中, int
占 32位, 第 1 位是 符号位, 其余 31 位是数字的二进制值.
在计算机中整数用 补码 表示.
原码: 符号位 和 数字的二进制表示.
反码: 在 原码 的基础上, 符号位不变, 其余位取反.
补码: 正数的补码就是原码本身, 负数的补码是 反码加1.
(decimal) (binary)
3 = 00000000 00000000 00000000 00000011
~3(补码) = 11111111 11111111 11111111 11111100
~3(原码) = 10000000 00000000 00000000 00000100
10000000 00000000 00000000 00000100
这就是 -4
的原码.
6 左移 <<
左移 会 把符号位当做普通的二进制位.
在左移完事后符号位不变的情况下, x 左移 n 位 相当于 x * 2n
.
例如:
3 << 2
结果为 12
.
(decimal) (binary)
3 = 0011
------------------ 左移2位(<<), 相当于: 3*(2*2)
12 = 1100
7 有符号右移 >>
有符号右移 不会 把符号位当做普通的二进制位.
对于正数, 有符号右移时, 高位(左边)补0;
对于负数, 有符号右移时, 高位(左边)补1;
例如:
-5 >> 2
结果为 -2
.
(decimal) (binary)
-5 = 111111111 11111111 11111111 1111011
------------------ 有符号右移 2位(>>)
-2 = 111111111 11111111 11111111 1111110
5 >> 2
结果为 1
.
(decimal) (binary)
5 = 000000000 00000000 00000000 0000101
------------------ 有符号右移 2位(>>) 相当于: 5/(2*2)
1 = 000000000 00000000 00000000 0000001
对于正数, x 有符号右移(>>) n 位 相当于 x / 2n
.
8 无符号右移 >>>
无符号右移 会 把符号位当做普通的二进制位.
不论正数还是负数, 无符号右移 >>> 高位(左边) 都补0.
(decimal) (binary)
-5 = 111111111 11111111 11111111 1111011
------------------ 无符号右移 2位(>>>)
结果 = 001111111 11111111 11111111 1111110
9 验证程序
public class TCheck {
public static void main(String[] args) {
int a = 0xf; // 15
printBinaryBeauty(a);
System.out.println("=====0====");
printBinaryBeauty(1 << 2); // 00000000 00000000 00000000 00000100
printBinaryBeauty(1 << 3); // 00000000 00000000 00000000 00001000
System.out.println("=====1====");
printBinaryBeauty(1 << 31); // 10000000 00000000 00000000 00000000
printBinaryBeauty(~(1 << 31)); // 01111111 11111111 11111111 11111111
System.out.println("=====2====");
printBinaryBeauty(-5); // 11111111 11111111 11111111 11111011
printBinaryBeauty(-5 >> 2); // 11111111 11111111 11111111 11111110
printBinaryBeauty(-5 >>> 2);// 00111111 11111111 11111111 11111110
System.out.println("=====3====");
printBinaryBeauty(5); // 00000000 00000000 00000000 00000101
printBinaryBeauty(5 >> 2); // 00000000 00000000 00000000 00000001
printBinaryBeauty(5 >>> 2); // 00000000 00000000 00000000 00000001
}
public static void printBinaryBeauty(int num) {
System.out.print(num + " 的二进制表示: ");
for (int i = 0; i < 32; i++) {
int bit = (num & (0x80000000 >>> i)) >>> (31 - i);
System.out.print(bit);
if ((i+1) % 8 == 0) {
System.out.print(" ");
}
}
System.out.println();
}
}