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 位对齐。

总结

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

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

相关推荐
D_aniel_4 分钟前
排序算法-堆排序
java·排序算法·堆排序
哞哞不熬夜16 分钟前
JavaEE--文件操作和IO
java·开发语言·windows·学习·java-ee·intellij-idea·idea
LUCIAZZZ24 分钟前
JVM之内存管理(二)
java·jvm·后端·spring·操作系统·springboot
向哆哆29 分钟前
Hibernate 性能优化:告别慢查询,提升数据库访问性能
java·数据库·性能优化·hibernate
小雅痞1 小时前
[Java][Leetcode middle] 80. 删除有序数组中的重复项 II
java·python·leetcode
小吕学编程1 小时前
Redis从基础到高阶应用:核心命令解析与延迟队列、事务消息实战设计
java·数据结构·redis
爱吃烤鸡翅的酸菜鱼1 小时前
Java【网络原理】(5)深入浅出HTTPS:状态码与SSL/TLS加密全解析
java·网络·后端·网络协议·http·https·ssl
途中刂1 小时前
第一章 初识Java
java·开发语言·笔记·学习·intellij-idea
苹果酱05672 小时前
Mac下Robotframework + Python3环境搭建
java·vue.js·spring boot·mysql·课程设计
有梦想的攻城狮2 小时前
spring中的@Qualifier注解详解
java·后端·spring·注解·qualifier