引言
Java位运算符直接操作二进制位(bit)
,适用于整数类型(byte, short, int, long, char),不兼容浮点数(float, double)。其核心价值在于底层计算优化
和高效算法实现
(如位图、加密算法)。Java共支持7种位运算符
。
一、基本位运算符
1、按位与(&)
- 规则:两操作数对应位
均为1时结果为1
,否则为0- 任何位与0相与结果为0(
屏蔽效果
) - 任何位与1相与保留原值(
透传效果
)
- 任何位与0相与结果为0(
java
int a = 60; // 二进制: 0011 1100
int b = 13; // 二进制: 0000 1101
int result = a & b; // 结果: 0000 1100 (十进制12)
- 典型应用:掩码操作(
提取特定位
)
java
// 提取最低4位
int value = 0b10101100; // 原数值
int mask = 0b00001111; // 掩码,表示只保留最低4位
int lowerNibble = value & mask; // 结果: 1100 (十进制12)
2、按位或(|)
- 规则:两操作数对应位
至少一个为1时结果为1
java
int a = 60; // 二进制:0011 1100
int b = 13; // 二进制:0000 1101
int result = a | b; // 结果:0011 1101 (十进制61)
- 典型应用:
组合位标志
java
final int READ = 1; // 0001 -> 表示读取权限
final int WRITE = 2; // 0010 -> 表示写入权限
final int EXECUTE = 4; // 0100 -> 表示执行权限
final int OTHER = 8; // 1000 -> 表示其他权限
int permissions = READ | WRITE; // 0011 (3),表示 同时拥有读取和写入权限
3、按位异或(^)
- 规则:两操作数对应位
不同时结果为1
,相同时为0- 归零律:
a ^ a = 0
- 恒等律:
a ^ 0 = a
- 交换律:
a ^ b = b ^ a
- 结合律:
(a ^ b) ^ c = a ^ (b ^ c)
- 可逆性:
a ^ b ^ b = a
(可应用于简单加密)
- 归零律:
java
int a = 60; // 二进制:0011 1100
int b = 13; // 二进制:0000 1101
int result = a ^ b; // 结果:0011 0001 (十进制49)
- 典型应用:
交换两个变量
(无需临时变量)
java
int x = 10, y = 20;
x = x ^ y;
// y转换为x值
y = x ^ y; // y = (x^y)^y = x
// x转换位y值
x = x ^ y; // x = (x^y)^x = y
4、按位取反(~)
- 规则:翻转操作数的每一位,
0→1, 1→0
(包括符号位)
java
int a = 5; // 二进制:0000 0101
int result = ~a; // 结果: 1111 1010 (十进制-6,快速计算-a-1=-6)
- 典型应用1:快速计算补码 - 负数的二进制表示
java
// 手动计算补码(求负数的二进制表示)
int positive = 42; // 0010 1010
int negative = ~positive + 1; // 1101 0110 (补码形式)
System.out.println("+42: " + Integer.toBinaryString(positive)); // 0010 1010
System.out.println("-42: " + Integer.toBinaryString(negative)); // 1111 1111 1111 1111 1111 1111 1101 0110
- 典型应用2:整数取反操作等价于:
~x = -x - 1
java
正数: 42 = 00000000 00000000 00000000 00101010
取反:~42 = 11111111 11111111 11111111 11010101 = -43
负数: -42 = 11111111 11111111 11111111 11010110
取反:~(-42) = 00000000 00000000 00000000 00101001 = 41
二、移位运算符
1、左移(<<)
- 规则:将二进制位
向左移动
指定位数,低位补0
- 效果:相当于乘以 <math xmlns="http://www.w3.org/1998/Math/MathML"> 2 n 2^n </math>2n(n为移位位数)
3<<4
等价于 <math xmlns="http://www.w3.org/1998/Math/MathML"> 3 × 2 4 3 \times 2^4 </math>3×24 =>48
-3<<4
等价于 <math xmlns="http://www.w3.org/1998/Math/MathML"> − 3 × 2 4 -3 \times 2^4 </math>−3×24 =>-48
2、带符号右移(>>)
- 规则:将二进制位
向右移动
,高位补符号位
(正数补0,负数补1) - 效果:相当于除以 <math xmlns="http://www.w3.org/1998/Math/MathML"> 2 n 2^n </math>2n(
向下取整
,相当于右侧溢出的位被丢弃) 69>>4
等价于 <math xmlns="http://www.w3.org/1998/Math/MathML"> 69 ÷ 2 4 = 4.3125 69 \div 2^4 = 4.3125 </math>69÷24=4.3125 => 向下取整 =>4
-69>>4
等价于 <math xmlns="http://www.w3.org/1998/Math/MathML"> − 69 ÷ 2 4 = − 4.3125 -69 \div 2^4 = -4.3125 </math>−69÷24=−4.3125 => 向下取整 =>-5
3、无符号右移(>>>)
- 规则:右移时
高位强制补0
(负数可能变正数) - >>和>>>比较
- 相同点:都是
向下取整
,右侧溢出的位被丢弃 - 不同点:>>>处理结果都是
非负数
- 相同点:都是
69>>>4
等价于 <math xmlns="http://www.w3.org/1998/Math/MathML"> 69 ÷ 2 4 = 4.3125 69 \div 2^4 = 4.3125 </math>69÷24=4.3125 => 向下取整 =>4
-69>>>4
结果:268435451
三、位运算高级技巧
1、高效乘除
java
// 乘以2的n次方
int multiplyByPowerOfTwo = num << n;
// 除以2的n次方(整数除法)
int divideByPowerOfTwo = num >> n;
2、奇偶判断
java
// 使用 &1 判断奇偶
boolean isEven = (num & 1) == 0;
3. 快速取整(取模)
java
// 对2的n次方取模(比%运算快5-10倍)
int mod = value & ((1 << n) - 1);
// 对256取模
int mod256 = value & 0xFF; // 十六进制0xFF => 二进制1111 1111 ==> 十进制255
// 对32取模
int mod32 = value & 0x1F; // 十六进制0x1F => 二进制0001 1111 ==> 十进制31
4、位标志管理
java
// 定义标志位
final int FLAG_A = 1 << 0; // 二进制0001,十进制1
final int FLAG_B = 1 << 1; // 二进制0010,十进制2
final int FLAG_C = 1 << 2; // 二进制0100,十进制4
// 设置标志
int flags = FLAG_A | FLAG_C; // 二进制0101,十进制5
// 检查标志
boolean hasFlagB = (flags & FLAG_B) != 0; // 0101 & 0010 = 0000
// 清除标志
flags &= ~FLAG_A; // 0101 & 1110 = 0100 结果对应FLAG_C,去掉了FLAG_A
四、性能对比实验
- 奇偶判断,传统方式与位运算方式性能比较(单位:亿次)
java
// 测试一亿次
int iterations = 100000000;
// 传统方式
long start = System.nanoTime();
for (int i = 0; i < iterations; i++) {
boolean result = (i % 2) == 0;
}
long modTime = System.nanoTime() - start;
// 位运算方式
start = System.nanoTime();
for (int i = 0; i < iterations; i++) {
boolean result = (i & 1) == 0;
}
long bitTime = System.nanoTime() - start;
System.out.println("取模方式: " + modTime + " ns");
System.out.println("位运算方式: " + bitTime + " ns");
System.out.println("性能提升: " + (modTime - bitTime) * 100 / modTime + "%");
典型测试结果:
java
取模方式: 2188666 ns
位运算方式: 789709 ns
性能提升: 63%
五、注意事项
1、左移位位数的有效范围
- 官方规定:实际移位位数:对
int
取模 32,对long
取模 64 - 理论int左移32位
没有意义
,所有位都被挤出去了,结果是 0
java
int x = 3;
x << 32; // 等价于 x << 0 (结果仍是 3)
x << 33; // 等价于 x << 1 (结果为 6)
2、运算符优先级陷阱
- 位运算符优先级
低于
比较运算符(如==
、>
)和算术运算符(+
、-
) - 建议:始终用
()
明确优先级
java
int a = 5, b = 3, c = 2;
int r1 = a & b + c; // 等价于 a & (b + c) = 5 & 5 = 5
int r2 = (a & b) + c; // (5 & 3) + 2 = 1 + 2 = 3
结语
位运算符是Java高效编程
的秘密武器。它们不仅提供接近硬件的操作能力,还能在算法优化
、内存管理
、网络通信
等场景发挥关键作用。虽然现代JVM已高度优化,但在性能敏感领域(如高频交易、游戏引擎、大数据处理),合理使用位运算仍能带来显著提升。
黄金法则:当你在处理二进制数据、标志位集合或需要极致性能时,位运算应是首选工具。但在常规业务逻辑中,优先选择可读性更高的标准操作