位运算

位运算

一、位运算基础概念

1.1 二进制表示

Java使用补码表示整数类型(byte/short/int/long):

  • 正数:原码=反码=补码
  • 负数:补码=反码+1(反码:符号位不变,其余位取反)

示例:

5   → 00000101
-5  → 11111011(8位byte类型)

1.2 位运算符概览

运算符 名称 示例 说明
& 按位与 a & b 两位同时为1时结果为1
| 按位或 a|b a、b任意一位为1时结果为1
^ 按位异或 a ^ b 两位不同时结果为1
~ 按位取反 ~a 所有位取反(包括符号位)
<< 左移位 a << n 左移n位,低位补0
>> 带符号右移 a >> n 右移n位,高位补符号位
>>> 无符号右移 a >>>n 右移n位,高位补0

二、基本位运算符详解

2.1 按位与(&)

特性:

  • 清零特定位:a & ~mask
  • 保留特定位:a & mask

示例:

int a = 0b1100; // 12
int b = 0b1010; // 10
int result = a & b; // 0b1000 → 8

2.2 按位或(|)

特性:

  • 设置特定位为1

示例:

int flags = 0;
flags |= 0b0001; // 设置第0位
flags |= 0b1000; // 设置第3位 → flags=0b1001

2.3 按位异或(^)

特性:

  • a ^ a = 0
  • a ^ 0 = a
  • 交换变量:a ^= b; b ^= a; a ^= b;

示例:

int x = 5; // 0101
int y = 3; // 0011
x ^= y;    // 0110 → 6
y ^= x;    // 0101 → 5
x ^= y;    // 0011 → 3

2.4 按位取反(~)

注意: 结果与数据类型位数有关

示例:

byte a = 0b00000000; // 0
~a → 0b11111111 → -1(补码表示)

三、位移运算符

3.1 左移运算符(<<)

公式: a << n = a × 2ⁿ
特性: 可能改变符号位

示例:

int a = 0b0011; // 3
a << 2 → 0b1100 → 12

3.2 带符号右移(>>)

特性: 保持符号位不变

示例:

int a = -8;      // 11111111 11111111 11111111 11111000
a >> 2 → -2      // 11111111 11111111 11111111 11111110

3.3 无符号右移(>>>)

特性: 高位始终补0

示例:

int a = -8; 
a >>> 2 → 1073741822 
// 00111111 11111111 11111111 11111110

四、高级技巧与应用

4.1 快速判断奇偶

boolean isEven = (n & 1) == 0; // 0为偶数,1为奇数

4.2 交换数值

a ^= b;
b ^= a;
a ^= b;

4.3 计算绝对值

int abs(int x) {
    int mask = x >> 31;
    return (x ^ mask) - mask;
}

4.4 查找唯一出现数字

(LeetCode 136题)

int singleNumber(int[] nums) {
    int result = 0;
    for (int num : nums) result ^= num;
    return result;
}

4.5 位掩码权限系统

final int READ = 1;    // 0001
final int WRITE = 2;   // 0010
final int EXECUTE = 4; // 0100

int permissions = 0;
permissions |= READ | WRITE; // 设置读写权限

// 检查权限
boolean canRead = (permissions & READ) != 0;

4.6 位计数(Brian Kernighan算法)

int countBits(int n) {
    int count = 0;
    while (n != 0) {
        n &= (n - 1);
        count++;
    }
    return count;
}

五、注意事项

  1. 位移长度限制:实际移动位数 = n % 32(int)或n % 64(long)

    int a = 1;
    a << 33 → 相当于 a << 1 → 2
    
  2. 符号扩展:右移运算符对符号位的处理差异

  3. 类型转换风险

    byte b = 0b10000000; // -128
    int i = b;           // -128(符号扩展)
    int j = b & 0xFF;    // 128(无符号处理)
    
  4. 优先级问题:位运算符优先级低于比较运算符

    if (a & 0xFF == 0) → 错误!应改为 if ((a & 0xFF) == 0)
    

六、性能优化应用

6.1 快速乘除

int x = 7;
x <<= 3; // 7*8=56
x >>= 2; // 56/4=14

6.2 判断2的幂

boolean isPowerOfTwo = (n & (n - 1)) == 0 && n != 0;

6.3 颜色分量提取

int color = 0xFF336699;
int alpha = (color >>> 24) & 0xFF;
int red = (color >>> 16) & 0xFF;
int green = (color >>> 8) & 0xFF;
int blue = color & 0xFF;

七、综合应用实例

7.1 位图存储

class BitSet {
    private long[] data;
    
    public BitSet(int capacity) {
        data = new long[(capacity + 63) / 64];
    }
    
    void set(int pos) {
        data[pos >>> 6] |= 1L << (pos & 0x3F);
    }
    
    boolean get(int pos) {
        return (data[pos >>> 6] & (1L << (pos & 0x3F))) != 0;
    }
}

7.2 位反转

int reverseBits(int n) {
    n = (n >>> 16) | (n << 16);
    n = ((n & 0xff00ff00) >>> 8) | ((n & 0x00ff00ff) << 8);
    n = ((n & 0xf0f0f0f0) >>> 4) | ((n & 0x0f0f0f0f) << 4);
    n = ((n & 0xcccccccc) >>> 2) | ((n & 0x33333333) << 2);
    n = ((n & 0xaaaaaaaa) >>> 1) | ((n & 0x55555555) << 1);
    return n;
}

八、总结

位运算在以下场景体现优势:

  1. 底层系统编程
  2. 高性能算法优化
  3. 内存敏感型应用
  4. 加密/压缩算法
  5. 图形处理

注意事项:

  • 优先保证代码可读性,必要时添加注释
  • 谨慎处理符号位和位移操作
  • 注意Java整型的固定位数特性
  • 进行位操作时考虑平台差异(Java跨平台特性保证位运算一致性)
posted @ 2025-03-02 13:29  咋还没来  阅读(48)  评论(0)    收藏  举报