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

总结

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

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

相关推荐
狗-sin狗36 分钟前
MyBatisSystemException:Parameter ‘item‘ not found.
java·mybatis
一个public的class40 分钟前
MyBatis-Plus的加载和初始化
java·mybatis·springboot
动亦定41 分钟前
如何理解java中Stream流?
java
热爱技术的小曹1 小时前
Spring6:10 数据校验-Validation
java·开发语言·spring
可了~1 小时前
Mybatis注解的基础操作——02
java·spring·mybatis
阿黄学技术1 小时前
深入了解Spring事务及其使用场景
java·后端·spring
乌海黑1 小时前
计算机网络快速入门
java·计算机网络·面试
三体世界2 小时前
C++ string的模拟实现
java·c语言·开发语言·c++·windows·visual studio·string
我欲混吃与等死2 小时前
LeetCode 86 Partition List 分区链表 Java
java·leetcode·链表·list
孔明click332 小时前
Sa-Token v1.41.0 发布 🚀,来看看有没有令你心动的功能!
java·sa-token·springboot·登录·权限·权限认证