0%

位运算总结

数据在计算机中都是以01的形态进行存储,位运算可以直接对01进行操作,其效率自然很高,在Java源码中是很常见的。这里总结位运算的概念以及常见的操作,后续遇到会补充。

位运算符

位运算是需要使用位运算符的,位运算符有如下几种(本表以java语言中的位运算为标准):

含义 符号 简述
按位与 a & b 同一得 1
按位或 a | b 有一得 1
按位异或 a ^ b 相同得 0
按位取反 ~a 取反
左移 a << b 向左移动,低位补零,高位舍弃
带符号右移 a >> b 向右移动,高位补原有高位,低位舍弃
无符号右移 a >>> b 忽略符号位,空位都以0补齐

位运算优先级

~的优先级最高,其次是<<、>>和>>>,再次是&,然后是^,优先级最低的是|。

位运算符在日常开发中也是 有许多应用场景的,具体场景将在下边代码中展示:

按位或 |

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* | 按位或 有一得1
* 比较m, n之间,换成二进制后谁的1最多
* 使用 按位或 | 计算 有一得一,与&清零不同的是使用 | 可以置1
* @param m
* @param n
*/
public static int test2(int m ,int n) {
// 7:111 8:0001 7|8 = 111(2) | 0001(2) = 1111(2) = 15
// 6:011 7:111 6|7 = 011(2) | 111(2) = 111(2) = 7
while ((m | m+1)<=n) {
m = (m | m+1);
}
return m;
}
```

### 按位与 &

```Java
/**
* & 按位与 同一得1
* 判断一个整数n是不是2的x次幂
* 若n&(n-1)=0 则说明n是2的x次幂
* 也可以这样说:循环结束后当ans=1时,说明n时2的x幂
* 按位与 & : 同一得一,可用于清零操作
* @param n
* @return ans 表示n转化成二进制数之后,1的个数
*/
public static int test1(int n) {
int ans = 0;
while (n != 0) {
ans++;
n &= (n-1);
System.out.println(n);
}
return ans;
}
```


### 异或 ^


```Java
/**
* ^ 异或 相同得0
* 可用于交换两个变量的数值,不用到带三个变量
* 交换律
* @param a , b
*/
public static void test3(int a, int b) {
a = a ^ b;
// a^b ^ b = a
b = a ^ b;
// a^b ^ a = b
a = a ^ b;
}

按位取反~

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 取反 ~
* 先对原数进行按位取反,然后减1,再进行取反得到一个数,最后加上负号即可
*
* 00000000 00000000 00000000 00000100 原值
* 11111111 11111111 11111111 11111011 取反
* 11111111 11111111 11111111 11111010 -1
* 00000000 00000000 00000000 00000101 取反
*/
public static void test4() {
int a = 4;
System.out.print(~4);
}

左移 <<

1
2
3
4
5
6
7
8
9
10
/**
* 左移 <<
*
* 00000000 00000000 00000000 00000101 左移2位后,低位补0
* 00000000 00000000 00000000 00010100 转为十进制为 20
*/
public static void test5() {
int a = 5;
System.out.print(a << 2);
}

右移 >>

1
2
3
4
5
6
7
8
9
10
/**
* 右移 >> 高位补符号位
*
* 00000000 00000000 00000000 00000101 右移2位后,高位补0
* 00000000 00000000 00000000 00000001 转为十进制为 1
*/
public static void test6() {
int a = 5;
System.out.print(a >> 2);
}

无符号右移 >>>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 无符号右移 >>> 高位补0
*
* >>>和>>的区别是:在执行运算时,>>>运算符的操作数高位补0,而>>运算符的操作数高位移入原来高位的值。
*
*/
public static void test7() {

/** 负数取值: 减一后按位取反 **/

/**
* -5 >> 2 情况
* 11111111 11111111 11111111 11111011 -5 的二进制
* 11111111 11111111 11111111 11111110 >> 2
* 10000000 00000000 00000000 00000010 减1,按位取反,值为-2
*/
System.out.println(-5 >> 2);// 结果是-2

/**
* -5 >>> 2 情况
* 11111111 11111111 11111111 11111011 -5 的二进制
* 00111111 11111111 11111111 11111110 >>> 2, 高位补0,此时为正数
*/
System.out.println(-5 >>> 2);// 结果是1073741822
}