Java 位运算符

位运算符是直接操作整数二进制位的运算符,它们主要用于底层编程、性能优化和特定算法。

目录

位运算符分类

1.基本位运算符

2.移位运算符

移位具体处理

(1)移位操作数处理

(2)移位数处理

位运算符的特点

1.只适用于整数类型:

2.运算前自动类型提升:

3.应用:

注意事项

1.运算符优先级问题

2.复合赋值运算符的隐式转换

3.数值问题

4.不可用于BigInteger


位运算符分类

1.基本位运算符

运算符名称描述示例
~按位取反翻转所有位(0变1,1变0)~0b1010 → 0b0101
&按位与两位都为1时结果为10b1100 & 0b1010 → 0b1000
|按位或任一位为1时结果为10b1100 | 0b1010→0b1110
^按位异或两位不同时结果为10b1100 ^ 0b1010 → 0b0110

2.移位运算符

运算符名称描述示例 
<<左移左移指定位数,低位补00b1100 << 2 → 0b110000 
>>算术右移右移指定位数,高位补符号位-8 >> 1 → -4
>>>逻辑右移右移指定位数,高位补0-8 >>> 1 → 2147483644

移位具体处理

移位运算的操作数始终以32位(int)或64位(long)的二进制补码形式处理

为什么是32位?
Java语言规范规定

  • int类型:所有比int小的整数类型(byte、short、char)在运算时会被自动提升为int(32位)。
  • long类型:如果操作数是long,则按64位处理。
  • 设计初衷:保证跨平台一致性(无论底层硬件是32位还是64位)。

二进制补码存储

  • 负数以补码形式存储,例如 -8 的32位表示:

             11111111 11111111 11111111 11111000

  • 正数直接存储原码 (正数的补码和原码相同),例如 8 的32位表示:

             00000000 00000000 00000000 00001000

(1)移位操作数处理

操作数类型实际运算位数示例
byte/short/char提升为32位byte b = 8; b << 2 → 按int处理
int32位8 << 2 → 操作32位
long64位8L << 2 → 操作64位

(2)移位数处理

  • int移位:int i ; i<<n  ; 若 n>32  , 则只需移位( n % 32)
8 << 34  // 实际是 8 << (34 % 32) = 8 << 2 = 32
  • long移位:long l ; l<<n  ; 若 n>64  , 则只需移位(n % 64)

8L << 66  // 实际是 8L << (66 % 64) = 8L << 2 = 32L

位运算符的特点

1.只适用于整数类型:

  • 有效类型:byte, short, int, long, char
  • 无效类型:float, double, boolean(布尔值的 & | ^ 是逻辑运算,注意按位取反运算符~ 不能直接用于 boolean 类型,如果需要布尔值的反向逻辑,应使用 逻辑非运算符 !)

为什么不能用于float/double?
设计原理:

  • 位运算符是设计用于整数二进制表示的操作
  • float和double采用IEEE 754浮点标准存储,其二进制结构与整数完全不同
  • 浮点数的位模式包含符号位、指数位和尾数位,直接进行位运算没有数学意义
float f = 1.5f;
// int result = f & 0x0F;  // 编译错误:位运算符不能应用于float

2.运算前自动类型提升:

byte a = 0b0011;
byte b = 0b0101;
int result = a & b;  // byte会先提升为int

3.应用:

  • 判断奇偶:(num & 1) == 0
  • 交换两数:a ^= b; b ^= a; a ^= b;
  • 取绝对值:(n ^ (n >> 31)) - (n >> 31)
  • 位移位操作(<<、>>、>>>)优化计算

快速乘除法(处理负数需要特别注意,因为简单的位移可能导致不符合预期的结果)

int x = 10;
x = x << 1;  // 相当于 x * 2 = 20
x = x >> 2;  // 相当于 x / 4 = 5

2的幂次方计算

int pow2 = 1 << n;  // 计算2的n次方

注意事项

1.运算符优先级问题

  • 移位运算符优先级低于算术运算符
int a = 5 + 3 << 2;  // 等价于(5+3)<<2=32,不是5+(3<<2)=17

2.复合赋值运算符的隐式转换

byte b = 10;
b |= 0b1000;  // 合法,相当于b = (byte)(b | 0b1000)
// b = b | 0b1000;  // 编译错误,需要强制转换

3.数值问题

  • 对负数进行右移操作时结果可能不符合直觉
//计算前将原码转为补码,按补码运算,运算完成转回原码
int negative = -8;       // 0xFFFFFFF8
int shifted = negative >> 1;  // 0xFFFFFFFC (-4)
int unsigned = negative >>> 1; // 0x7FFFFFFC (2147483644)

4.不可用于BigInteger

  • 虽然BigInteger存储大整数,但需要使用专门的方法而非位运算符
BigInteger bi = new BigInteger("10");
// int wrong = bi & 1;  // 编译错误
int right = bi.and(BigInteger.ONE).intValue();

为什么位运算符不能直接用于 BigInteger/BigDecimal?

(1)设计目的不同

  • BigInteger/BigDecimal 是高精度数值类,用于处理任意大小的整数或精确小数。
  • 位运算符是为固定位数的原始类型(如 int、long)设计的,与高精度运算的定位冲突。

(2)内部存储方式

  • BigInteger 内部使用 可变长度的 int[] 存储数据,而非固定的二进制补码形式。
  • BigDecimal 内部基于 BigInteger + 小数位数(scale),更无位操作的意义。

(3)运算符重载限制

  • Java 不支持运算符重载,无法为自定义类(如 BigInteger)重定义 &、| 等操作符。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值