04_位运算符(按位与 按位或 按位异或 按位取反 左移 右移 无符号右移)
一、位运算符概述
位运算符是对整数的二进制位进行直接操作的运算符,适用于byte、short、int、long等整数类型(char会先转换为整数再运算)。位运算直接操作内存中的二进制数据,执行效率高,常用于底层编程、算法优化、权限控制等场景。
Java 中的位运算符可分为两大类:
- 位逻辑运算符:按位与(&)、按位或(|)、按位异或(^)、按位取反(~)
- 位移运算符:左移(<<)、右移(>>)、无符号右移(>>>)
二、位逻辑运算符
2.1 按位与(&)
运算规则
对两个操作数的每一位进行与操作:
对应位都为1时,结果位为 1
否则为 0
| 操作数 1 位 | 操作数 2 位 | 结果位(操作数 1 & 操作数 2) |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
代码示例(以int类型为例,仅展示有效位)
int a = 3; // 二进制:0000 0011
int b = 5; // 二进制:0000 0101
int result = a & b; // 二进制:0000 0001 → 十进制:1
System.out.println(result); // 输出1
特点与应用
- 清零特性:与 0 按位与可将对应位清零(如num & 0xffffff00可清掉低 8 位)
- 保留指定位:与特定掩码按位与可保留需要的位(如num & 0xff保留低 8 位)
- 判断奇偶:num & 1 == 1 表示奇数(二进制最后一位为 1)
2.2 按位或(|)
运算规则
对两个操作数的每一位进行或操作:
- 对应位至少有一个为 1时,结果位为 1,否则为0
| 操作数 1 位 | 操作数 2 位 | 结果位(操作数 1 | 操作数 2) |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
代码示例
int a = 3; // 二进制:0000 0011
int b = 5; // 二进制:0000 0101
int result = a | b; // 二进制:0000 0111 → 十进制:7
System.out.println(result); // 输出7
特点与应用
- 置位特性:与 1 按位或可将对应位置为 1(如num | 0x0000000f可将低 4 位置 1)
- 权限控制:常用于组合多个权限标识(如READ | WRITE表示 “读 + 写” 权限)
2.3 按位异或(^)
运算规则
对两个操作数的每一位进行异或操作:
- 对应位不同时,结果位为 1
- 对应位相同时,结果位为 0
| 操作数 1 位 | 操作数 2 位 | 结果位(操作数 1 ^ 操作数 2) |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
代码示例
int a = 3; // 二进制:0000 0011
int b = 5; // 二进制:0000 0101
int result = a ^ b; // 二进制:0000 0110 → 十进制:6
System.out.println(result); // 输出6
特点与应用
- 还原特性:一个数异或同一个数两次会还原(a ^ b ^ b = a),可用于简单加密
- 交换变量:无需临时变量交换两个数(a = a ^ b; b = a ^ b; a = a ^ b;)
- 翻转位:与 1 异或可翻转对应位(0 变 1,1 变 0)
2.4 按位取反(~)
运算规则
对操作数的每一位取反(0 变 1,1 变 0),是单目运算符(仅需一个操作数)。
| 操作数位 | 结果位(~ 操作数) |
|---|---|
| 0 | 1 |
| 1 | 0 |
代码示例
int a = 3; // 二进制(32位):00000000 00000000 00000000 00000011
int result = ~a; // 二进制:11111111 11111111 11111111 11111100 → 十进制:-4
System.out.println(result); // 输出-4
特点与注意事项
- 符号位影响:Java 中整数是有符号数(最高位为符号位:0 表示正数,1 表示负数),因此取反后正数会变为负数,负数会变为正数
- 计算公式:~n = -(n + 1)(如~3 = -4,~-4 = 3)
- 对byte、short等类型操作时,会先转换为int再取反
三、位移运算符
位移运算符是将整数的二进制位向指定方向移动的运算符,移动后空位用特定值填充。
3.1 左移(<<)
运算规则
将二进制位向左移动指定位数,右边空位补 0,左边溢出的高位丢弃。
语法:操作数 << 移动位数
代码示例
int a = 3; // 二进制:0000 0011
int result = a << 2; // 左移2位 → 0000 1100 → 十进制:12
System.out.println(result); // 输出12
特点与应用
- 数学意义:a << b 等价于 a * 2^b(不溢出时),如3 << 2 = 3 * 4 = 12
- 效率优势:左移运算比乘法运算更高效(底层直接操作二进制)
- 注意溢出:当移动位数过大时,可能导致结果溢出(如1 << 31在int中会变为负数)
3.2 右移(>>,算术右移)
运算规则
将二进制位向右移动指定位数,左边空位补符号位(正数补 0,负数补 1),右边溢出的低位丢弃。
语法:操作数 >> 移动位数
代码示例
// 正数右移
int a = 6; // 二进制:0000 0110
int result1 = a >> 2; // 右移2位 → 0000 0001 → 十进制:1
System.out.println(result1); // 输出1
// 负数右移(符号位补1)
int b = -6; // 二进制(简化):1111 1010
int result2 = b >> 2; // 右移2位 → 1111 1110 → 十进制:-2
System.out.println(result2); // 输出-2
特点与应用
- 数学意义:a >> b 等价于 a / 2^b(向下取整),如6 >> 2 = 1,-6 >> 2 = -2
- 保持原数的符号不变(正数仍为正数,负数仍为负数)
3.3 无符号右移(>>>,逻辑右移)
运算规则
将二进制位向右移动指定位数,左边空位补 0(无论原数正负),右边溢出的低位丢弃。
语法:操作数 >>> 移动位数
代码示例
// 正数无符号右移(与>>结果相同)
int a = 6; // 二进制:0000 0110
int result1 = a >>> 2; // 右移2位 → 0000 0001 → 十进制:1
System.out.println(result1); // 输出1
// 负数无符号右移(左边补0,结果为正数)
int b = -6; // 二进制(32位):11111111 11111111 11111111 11111010
int result2 = b >>> 2; // 右移2位 → 00111111 11111111 11111111 11111110 → 十进制:1073741822
System.out.println(result2); // 输出1073741822
特点与应用
- 无符号特性:无论原数正负,移位后结果均为正数(左边补 0)
- 适用于无符号整数场景(如 IP 地址解析、哈希计算)
- 对byte、short操作时,会先转换为int再移位
四、位运算符优先级与结合性
4.1 优先级顺序(由高到低)
- 按位取反(~)
- 左移(<<)、右移(>>)、无符号右移(>>>)
- 按位与(&)
- 按位异或(^)
- 按位或(|)
4.2 结合性
- 单目运算符(~):从右到左
- 双目运算符(&、|、^、<<、>>、>>>):从左到右
4.3 示例:复杂位运算
int a = 5; // 0101
int b = 3; // 0011
// 运算顺序:先移位,再异或,最后与
int result = (a << 1) ^ b & 0x0f;
// 步骤解析:
// 1. a << 1 → 1010(10)
// 2. b & 0x0f → 0011(3)
// 3. 10 ^ 3 → 1001(9)
System.out.println(result); // 输出9
建议:复杂位运算用括号明确顺序,提高可读性。
五、位运算符与逻辑运算符的区别
| 运算符 | 类型 | 操作对象 | 短路特性 | 结果类型 |
|---|---|---|---|---|
| & | 位逻辑 | 二进制位 | 无(两边都执行) | 整数 |
| && | 逻辑与 | 布尔值 | 有(左为 false 则右不执行) | 布尔值 |
| | | 位逻辑 | 二进制位 | 无(两边都执行) | 整数 |
| || | 逻辑或 | 布尔值 | 有(左为 true 则右不执行) | 布尔值 |
六、位运算符的应用场景
6.1 高效计算
利用位运算替代乘除、取余等运算,提升效率:
// 乘2^n:a << n
int multiply = 5 << 3; // 5 * 8 = 40
// 除2^n(向下取整):a >> n
int divide = 25 >> 2; // 25 / 4 = 6
// 取余2^n:a & (2^n - 1)
int mod = 25 & 3; // 25 % 4 = 1(3 = 2^2 - 1)
6.2 权限控制
用二进制位表示不同权限,通过位运算组合或判断权限:
// 定义权限(每一位代表一种权限)
public static final int READ = 1 << 0; // 0001(1)
public static final int WRITE = 1 << 1; // 0010(2)
public static final int EXEC = 1 << 2; // 0100(4)
// 组合权限(读+写)
int permissions = READ | WRITE; // 0011(3)
// 判断是否有写权限
boolean hasWrite = (permissions & WRITE) != 0; // true
// 移除读权限
permissions = permissions & ~READ; // 0010(2)
6.3 数据加密与解密
利用异或的还原特性实现简单加密:
String plaintext = "hello";
int key = 123; // 密钥
// 加密:每个字符与密钥异或
char[] encrypted = new char[plaintext.length()];
for (int i = 0; i < plaintext.length(); i++) {
encrypted[i] = (char) (plaintext.charAt(i) ^ key);
}
// 解密:再次异或密钥还原
char[] decrypted = new char[encrypted.length];
for (int i = 0; i < encrypted.length; i++) {
decrypted[i] = (char) (encrypted[i] ^ key);
}
System.out.println(new String(decrypted)); // 输出"hello"
6.4 交换变量(无临时变量)
int a = 5, b = 10;
a = a ^ b; // a = 5 ^ 10
b = a ^ b; // b = (5 ^ 10) ^ 10 = 5
a = a ^ b; // a = (5 ^ 10) ^ 5 = 10
// 结果:a=10,b=5
七、注意事项
- 类型转换:对byte、short、char操作时,会先自动转换为int再运算,结果为int类型(如需原类型需强制转换)
byte b = 3;
byte result = (byte) (b << 2); // 需强制转换为byte
- 移动位数限制:移动位数超过操作数的位数时,会先对移动位数取模(如int为 32 位,a << 33等价于a << 1)
- 溢出问题:左移可能导致正数变负数(因符号位变化),需注意数据范围
int maxInt = Integer.MAX_VALUE; // 2^31 - 1
int overflow = maxInt << 1; // 结果为-2(溢出)
- 可读性权衡:位运算效率高但可读性差,非性能敏感场景建议优先考虑代码可读性
八、总结
位运算符通过直接操作二进制位实现高效运算,主要包括:
- 位逻辑运算:&(按位与)、|(按位或)、^(按位异或)、~(按位取反)
- 位移运算:<<(左移)、>>(右移,补符号位)、>>>(无符号右移,补 0)
位运算适用于底层编程、算法优化、权限控制等场景,但需注意符号位影响、溢出问题和代码可读性。合理使用位运算可显著提升程序性能,是 Java 高级编程的重要基础。

浙公网安备 33010602011771号