位运 算 符 中 ,操 作 数 只 能 为 整 型 和字 符 型 数 据 。
按位与(&)
操作数1 | 0 | 0 | 1 | 1 |
---|---|---|---|---|
操作数2 | 0 | 1 | 0 | 1 |
按位与 | 0 | 0 | 0 | 1 |
按位或(|)
操作数1 | 0 | 0 | 1 | 1 |
---|---|---|---|---|
操作数2 | 0 | 1 | 0 | 1 |
按位或 | 0 | 1 | 1 | 1 |
按位非(~)
操作数 | 0 | 1 |
---|---|---|
按位非 | 1 | 0 |
按位异或(^)
操作数1 | 0 | 0 | 1 | 1 |
---|---|---|---|---|
操作数2 | 0 | 1 | 0 | 1 |
按位异或 | 0 | 1 | 1 | 0 |
左位移(<<)
溢出截断,低位补0;
右位移(>>)
溢出截断,高位补符号位;
无符号右移(>>>)
溢出截断,高位补0;
位运算运算法则
1. a^a = 0
2. a^0 = a
3. a^b = b^a
4. a^b^c = (a^b)^c = a^(b^c)
5. a^b^c=0
a=b^c^d
b=c^d^a
c=d^a^b
d=a^b^c
常见位运算
1. m*2^n
System.out.println("2^3=" + (1 << 3));// 2^3=8
System.out.println("3*2^3=" + (3 << 3));// 3*2^3=24
System.out.println("5*2^3=" + (5 << 3));// 5*2^3=40
2. 判断一个数n的奇偶性
二进制表示一个数的奇偶性主要看最后一位 为1 则为奇数
为0 则为偶数
System.out.println((5 & 1) == 1 ? "奇数" : "偶数"); // 奇数
System.out.println((6 & 1) == 1 ? "奇数" : "偶数"); // 偶数
System.out.println((0 & 1) == 1 ? "奇数" : "偶数"); // 偶数
System.out.println((-1 & 1) == 1 ? "奇数" : "偶数"); // 奇数
System.out.println((-2 & 1) == 1 ? "奇数" : "偶数"); // 偶数
3. 不用临时变量交换两个数
int x = 5;
int y = 6;
x = x ^ y;
y = x ^ y;
x = x ^ y;
System.out.println(x);// 6
System.out.println(y);// 5
4. 取绝对值
System.out.println((-5 ^ (-5 >> 31)) - (-5 >> 31));// 5
System.out.println((0 ^ (0 >> 31)) - (0 >> 31));// 0
System.out.println((5 ^ (5 >> 31)) - (5 >> 31));// 5
System.out.println((6 ^ (6 >> 31)) - (6 >> 31));// 6
System.out.println((7 ^ (7 >> 31)) - (7 >> 31));// 7
4个字节 32位,a>>31取得a的符号;
任何正数右移31后只剩符号位0,溢出的31位截断,空出的31位补符号位0,最终结果为0
;
任何负数右移31后只剩符号位1,溢出的31位截断,空出的31位补符号位1,最终结果为 -1
;
正数 ^ 0 = 正数本身(二进制不变);
负数 ^ -1 = 它的绝对值 -1(二进制翻转每一位);
以上参考:Java位运算原理及使用讲解
5. 找出没有重复的数
int find(int[] nums){
int tmp = nums[0];
for(int i = 1;i < nums.length; i++)
tmp ^= arr[i];
return tmp;
}
总结小经验
- 4个字节32位的整数,右移31操作可以取得符号位;
------------------------------------
00000000 01010000 10100000 01011000|
------------------------------------
右移31位
------------------------------------
0|0000000 01010000 10100000 01011000
------------------------------------
空位补0
------------------------------------
00000000 00000000 00000000 00000000|
------------------------------------
最终结果为 0
------------------------------------
10000000 01010000 10100000 01011000|
------------------------------------
右移31位
------------------------------------
1|0000000 01010000 10100000 01011000
------------------------------------
空位补0
------------------------------------
11111111 11111111 11111111 11111111|
------------------------------------
最终结果为 -1
- 任意二进制 & -1, 会把原二进制里的1找出来;
举例:
0000 0101 1010
& 1111 1111 1111
---------------------
0000 0101 1010
- 任意二进制 | 0, 会把原二进制里的0找出来
举例:
0000 0101 1010
| 0000 0000 0000
---------------------
0000 0101 1010
- 任意二进制 ^ 0, 会保持原二进制;
举例:
0000 0101 1010
^ 0000 0000 0000
---------------------
0000 0101 1010
- 任意二进制 ^ -1, 会把每一位给翻转 (个人理解就是无符号位的取反);
负数 原码 1000 1001 1010 1011 1100 1101 1110 1111
负数绝对值 0000 0001 0010 0011 0100 0101 0110 0111
反 码 1111 1110 1101 1100 1011 1010 1001 1000
负数反码+负数绝对值
1111 1111 1111 1111 1111 1111 1111 1111
1111 为 -1 的补码,在实际开发中就代表了-1;
综上 任意二进制 ^ -1, 会把每一位给翻转;
举例:
0000 0101 1010
^ 1111 1111 1111
---------------------
1111 1010 0101
以上参考:几种常见的位运算