27. Java中,使用按位运算符和移位运算符

27. Java中,使用按位运算符和移位运算符

Java 提供了按位运算符和移位运算符,这些运算符用于直接操作整数类型的二进制位。虽然它们在日常编程中不常用,但在一些性能要求较高的应用中,例如图像处理、加密或其他低级操作中,可能会非常有用。

1. 按位补码运算符 (~)

**按位补码运算符(~)**会反转操作数的每一位,将 0 变为 11 变为 0。例如,如果某个整数的二进制表示是 00000000,应用 ~ 运算符后,它将变为 11111111

示例:
java 复制代码
int number = 0x00000000;  // 00000000(二进制)
int result = ~number;     // 11111111(二进制)

System.out.println(result);  // 输出 -1

2. 按位运算符

按位运算符用于逐位对整数类型的二进制表示进行操作。

  • 按位 AND (&) :将两个操作数的每一位进行 AND 运算,只有两个操作数的对应位都为 1 时,结果才为 1

    示例:

    java 复制代码
    int a = 0x6;  // 0110
    int b = 0x3;  // 0011
    System.out.println(a & b);  // 输出 2 (0010)
  • 按位 OR (|) :将两个操作数的每一位进行 OR 运算,只要两个操作数的对应位有一个为 1,结果就为 1

    示例:

    java 复制代码
    int a = 0x6;  // 0110
    int b = 0x3;  // 0011
    System.out.println(a | b);  // 输出 7 (0111)
  • 按位 XOR (^) :将两个操作数的每一位进行 XOR 运算,只有两个操作数的对应位不相同时,结果才为 1

    示例:

    java 复制代码
    int a = 0x6;  // 0110
    int b = 0x3;  // 0011
    System.out.println(a ^ b);  // 输出 5 (0101)

3. 移位运算符

  • 左移运算符 (<<):将操作数的位向左移动指定的位数。左移操作会将零填充到最右侧。

    示例:

    java 复制代码
    int a = 5;   // 二进制表示为 0000000000000101
    System.out.println(a << 1);  // 输出 10 (0000000000001010)
  • 有符号右移 (>>) :将操作数的位向右移动指定的位数。右移时,符号位会被扩展。如果原数是正数,左侧填充 0;如果是负数,左侧填充 1

    示例:

    java 复制代码
    int a = -8;  // 二进制表示为 1111 1111 1111 1111 1111 1111 1111 1000
    System.out.println(a >> 2);  // 输出 -2 (1111 1111 1111 1111 1111 1111 1111 1110)
    步骤 1:确定 -8 的二进制补码表示

    Java 中,int 类型是 32 位有符号整数,负数以补码形式存储。求 -8 的补码步骤如下:

    1. 先求 8 的二进制原码 :8 的二进制表示为 0000 0000 0000 0000 0000 0000 0000 1000
    2. 对原码取反 :得到反码 1111 1111 1111 1111 1111 1111 1111 0111
    3. 反码加 1 :得到 -8 的补码 1111 1111 1111 1111 1111 1111 1111 1000
    步骤 2:进行有符号右移操作

    有符号右移运算符 >> 会将二进制数向右移动指定的位数,同时保持符号位不变。这里要将 -8 的补码右移 2 位,即 1111 1111 1111 1111 1111 1111 1111 1000 右移 2 位。

    • 右边移出的两位(最低的两个 0)被丢弃。
    • 左边空出的两位用符号位(最高位的 1)填充,得到 1111 1111 1111 1111 1111 1111 1111 1110
    步骤 3:将右移后的补码转换为十进制数

    右移后的结果 1111 1111 1111 1111 1111 1111 1111 1110 是补码形式,要得到其十进制值,需将补码转换为原码,步骤如下:

    1. 补码减 1 :得到反码 1111 1111 1111 1111 1111 1111 1111 1101
    2. 反码取反 :得到原码 1000 0000 0000 0000 0000 0000 0000 0010,其十进制值为 -2。
  • 无符号右移 (>>>):将操作数的位向右移动指定的位数,左侧始终填充 0。

    示例:

    java 复制代码
    int a = -8;  // 二进制表示为 1111111111111000
    System.out.println(a >>> 2);  // 输出 1073741822 (00111111111111111111111111111110)
    步骤 1:确定 -8 的二进制补码表示

    在 Java 里,int 类型为 32 位有符号整数,负数以补码形式存储。求 -8 的补码可按以下步骤进行:

    1. 得出 8 的二进制原码 :8 的二进制表示是 0000 0000 0000 0000 0000 0000 0000 1000
    2. 对原码取反 :得到反码 1111 1111 1111 1111 1111 1111 1111 0111
    3. 反码加 1 :得到 -8 的补码 1111 1111 1111 1111 1111 1111 1111 1000
    步骤 2:执行无符号右移操作

    无符号右移运算符 >>> 会二进制数向右移动指定的位数,无论该数是正数还是负数,左边空出的位都用 0 填充。这里要把 -8 的补码右移 2 位,也就是对 1111 1111 1111 1111 1111 1111 1111 1000 进行右移操作。

    • 右边移出的两位(最低的两个 0)被丢弃。
    • 左边空出的两位用 0 填充,得到 0011 1111 1111 1111 1111 1111 1111 1110
    步骤 3:将右移后的二进制数转换为十进制数

    右移后的结果 0011 1111 1111 1111 1111 1111 1111 1110 最高位是 0,表示这是一个正数,可通过按位权展开来计算其十进制值:

4. 按位运算符示例:按位 AND 运算符

下面的 BitDemo 程序演示了如何使用按位 AND 运算符将数字 2 打印到标准输出:

java 复制代码
class BitDemo {
    public static void main(String[] args) {
        int bitmask = 0x000F;  // 0000 0000 0000 1111(十六进制掩码)
        int val = 0x2222;      // 0010 0010 0010 0010(十六进制数值)

        // 使用按位 AND 运算符
        System.out.println(val & bitmask);  // 输出 2 (二进制 0000 0010)
    }
}

程序输出:

java 复制代码
2
解释:
  • bitmask = 0x000F :这是一种掩码,它的二进制表示是 0000 0000 0000 1111。这意味着它只保留了整数的低 4 位。
  • val = 0x2222 :这是一个十六进制数,二进制表示为 0010 0010 0010 0010
  • 按位 AND 运算 :通过 val & bitmask,我们将 valbitmask 进行按位与运算,结果为 2,因为只有 val 的低 4 位与 bitmask 的低 4 位对齐。

总结

  • 按位运算符&, |, ^, ~)允许我们直接操作整数的二进制位,适用于低级操作和性能优化。
  • 移位运算符<<, >>, >>>)用于将二进制位向左或向右移动,适用于位移操作或快速乘除。
  • 这些运算符有助于进行更加精细的位级控制,例如在图像处理、加密和算法优化中常见。

虽然这些运算符在常规应用中不太常用,但在需要处理二进制数据时,它们是非常强大的工具。

相关推荐
xexpertS14 小时前
队列积压治理:如何避免异步系统出现难以恢复的消息积压
java·开发语言
阿维的博客日记1 天前
MultipartFile 是不是表示仅仅是一个分片?
java·后端·spring·multipartfile
程序员无隅1 天前
Coding Agent 为什么压缩上下文后还能继续工作?上下文模块设计拆解
java·开发语言·数据库
Python+991 天前
Java 枚举类(Enum)详解:从基础到高级应用
java·开发语言·python
二炮手亮子1 天前
浅记java线程池
java·开发语言
一路向北North1 天前
Spring Security OAuth2.0(23):分布式系统授权-转发明文给微服务
java·spring·微服务
爱吃牛肉的大老虎1 天前
rust基础之环境搭建
java·开发语言·rust
tellmewhoisi1 天前
多版本共用redis的token有效期校验(过期重新登录)
java·redis·缓存
疯狂打码的少年1 天前
【软件工程】结构化设计:模块独立性与耦合内聚
java·开发语言·笔记·软件工程
乐观的Terry1 天前
3、数据库设计与领域实体
java·数据库·spring boot·spring cloud·ai编程