Java-day05

引入:

在 Java 编程中,运算符是构建表达式和实现逻辑的基础元素。从简化代码的结合运算符,到直接操作二进制位的位运算与移位运算,每种运算符都有其独特的应用场景和性能优势。本文将围绕**结合运算符**、**位运算**(按位与、或、异或)和**移位运算**(左移、右移、无符号右移)三大板块展开,通过原理讲解、代码示例和性能对比,帮助读者深入理解这些运算符的底层逻辑与实战价值,为编写高效、简洁的 Java 代码奠定基础。

一、结合运算符:简化赋值操作

结合运算符是 Java 中用于简化赋值表达式的语法糖,其核心作用是将“操作 + 赋值”两个步骤合并为一个操作,让代码更简洁易读。

 1.1 结合运算符的基本语法

结合运算符的通用形式为 `操作符= `,其中操作符可以是 `+`、`-`、`*`、`/`、`%`、`&`、`|`、`^`、`<<`、`>>`、`>>>` 等。例如:

- `x = x + 4` 可简化为 `x += 4`;

- `x = x * 4` 可简化为 `x *= 4`;

- 位运算也可结合,如 `x = x & 4` 可简化为 `x &= 4`。

**代码示例**:

```java

public class CompoundOperatorDemo {

    public static void main(String[] args) {

        int x = 5;

        // 传统赋值方式

        x = x + 4;

        System.out.println("x = x + 4: " + x); // 输出:9

       

        x = 5; // 重置x

        // 结合运算符简化

        x += 4;

        System.out.println("x += 4: " + x); // 输出:9

       

        // 乘法结合运算符

        x = 3;

        x *= 5;

        System.out.println("x *= 5: " + x); // 输出:15

    }

}

```

 1.2 结合运算符的优势

- **代码简洁性**:减少重复变量书写,提升代码可读性,尤其在复杂表达式中效果更明显;

- **运算效率**:编译器会对结合运算符进行优化,其执行效率与传统赋值方式一致,无性能损耗;

- **类型兼容性**:结合运算符会自动处理类型转换(如 `byte`、`short` 类型的自增不会溢出,编译器会隐式强转)。

**注意事项**:结合运算符的优先级低于大部分算术运算符,若表达式中存在其他运算,需注意加括号明确优先级。例如 `x += y * 2` 等价于 `x = x + (y * 2)`,而非 `(x + y) * 2`。

 二、位运算:直接操作二进制位

位运算是对整数类型(`byte`、`short`、`int`、`long`)的二进制位直接进行操作,包括**按位与(&)**、**按位或(|)**、**按位异或(^)**三种核心操作,常用于底层系统编程、数据压缩、加密算法等场景。

 2.1 按位与(&):同 1 则 1,否则 0

按位与操作的规则是:两个操作数的对应二进制位**同时为 1**时,结果位为 1,否则为 0。

**原理示例**:计算 `10 & -12`(以 8 位补码为例)

- `10` 的补码:`00001010`

- `-12` 的补码:`11110100`(原码 `10001100` → 反码 `11110011` → 补码 `11110100`)

- 按位与结果:`00000000`(即十进制 0)

**代码示例**:

```java

public class BitAndDemo {

    public static void main(String[] args) {

        int a = 10; // 00001010

        int b = -12; // 11110100

        int result = a & b;

        System.out.println("10 & -12 = " + result); // 输出:0

       

        // 计算 -8 & -9

        int c = -8; // 11111000

        int d = -9; // 11110111

        result = c & d;

        System.out.println("-8 & -9 = " + result); // 输出:-16(补码 11110000 对应十进制 -16)

    }

}

```

**应用场景**:

- 位掩码:用于标记状态(如 `result & 0b1000` 判断第 4 位是否为 1);

- 清 0 操作:将变量的某几位强制置 0(如 `x & 0xFFFFFF00` 清掉低 8 位)。

 2.2 按位或(|):有 1 则 1,否则 0

按位或操作的规则是:两个操作数的对应二进制位**至少有一个为 1**时,结果位为 1,否则为 0。

**原理示例**:计算 `10 | -8`(以 8 位补码为例)

- `10` 的补码:`00001010`

- `-8` 的补码:`11111000`

- 按位或结果:`11111010`(即十进制 -6)

**代码示例**:

```java

public class BitOrDemo {

    public static void main(String[] args) {

        int a = 10; // 00001010

        int b = -8; // 11111000

        int result = a | b;

        System.out.println("10 | -8 = " + result); // 输出:-6

       

        // 计算 -42 | -89

        int c = -42; // 11010110

        int d = -89; // 10100111

        result = c | d;

        System.out.println("-42 | -89 = " + result); // 输出:-9(补码 11110111 对应十进制 -9)

    }

}

```

**应用场景**:

- 置 1 操作:将变量的某几位强制置 1(如 `x | 0x000000FF` 置位低 8 位);

- 合并状态:将多个布尔状态合并到一个整数中(如权限控制,每一位代表一种权限)。

2.3 按位异或(^):不同则 1,相同则 0

按位异或操作的规则是:两个操作数的对应二进制位**不同**时,结果位为 1,**相同**时为 0。

**原理示例**:计算 `10 ^ -8`(以 8 位补码为例)

- `10` 的补码:`00001010`

- `-8` 的补码:`11111000`

- 按位异或结果:`11110010`(即十进制 -14)

**代码示例**:

```java

public class BitXorDemo {

    public static void main(String[] args) {

        int a = 10; // 00001010

        int b = -8; // 11111000

        int result = a ^ b;

        System.out.println("10 ^ -8 = " + result); // 输出:-14

       

        // 异或的特性:a ^ a = 0,a ^ 0 = a

        int x = 5;

        System.out.println("x ^ x = " + (x ^ x)); // 输出:0

        System.out.println("x ^ 0 = " + (x ^ 0)); // 输出:5

    }

}

```

**应用场景**:

- 交换两个数(无需临时变量):`a = a ^ b; b = a ^ b; a = a ^ b;`;

- 奇偶性判断:`x ^ 1` 可快速切换奇偶(偶数 ^ 1 = 奇数,奇数 ^ 1 = 偶数);

- 加密算法:简单的异或加密(明文 ^ 密钥 = 密文,密文 ^ 密钥 = 明文)。

 三、移位运算:高效的乘除与位操作

移位运算是对二进制位进行左移或右移的操作,包括**左移(<<)**、**右移(>>)**和**无符号右移(>>>)**三种,其核心优势是**性能远高于普通乘除运算**,常用于底层优化和位操作场景。

 3.1 左移(<<):舍弃高位,低位补 0

左移运算的规则是:将操作数的二进制位**向左移动指定位数**,舍弃左边高位,右边空出的位置用 0 填补。左移 n 位等价于**乘以 2 的 n 次幂**(若不溢出)。

**原理示例**:计算 `-8 << 2`(以 8 位补码为例)

- `-8` 的补码:`11111000`

- 左移 2 位后:`11100000`(补码)→ 反码 `11011111` → 原码 `10100000`(即十进制 -32)

- 验证:`-8 × 2² = -8 × 4 = -32`,与移位结果一致。

**代码示例**:

```java

public class LeftShiftDemo {

    public static void main(String[] args) {

        int a = -8;

        int result = a << 2;

        System.out.println("-8 << 2 = " + result); // 输出:-32

       

        // 左移实现乘法

        int b = 5;

        System.out.println("5 << 1 = " + (b << 1)); // 5 × 2 = 10

        System.out.println("5 << 2 = " + (b << 2)); // 5 × 4 = 20

    }

}

```

 3.2 右移(>>):高位补符号位,低位舍弃

右移运算的规则是:将操作数的二进制位**向右移动指定位数**,低位舍弃;**正数高位补 0,负数高位补 1**(即补符号位)。右移 n 位等价于**除以 2 的 n 次幂**(向下取整)。

**原理示例**:计算 `-8 >> 2`(以 8 位补码为例)

- `-8` 的补码:`11111000`

- 右移 2 位后:`11111110`(补码)→ 反码 `11111101` → 原码 `10000010`(即十进制 -2)

- 验证:`-8 ÷ 2² = -8 ÷ 4 = -2`,与移位结果一致。

**代码示例**:

```java

public class RightShiftDemo {

    public static void main(String[] args) {

        int a = -8;

        int result = a >> 2;

        System.out.println("-8 >> 2 = " + result); // 输出:-2

       

        int b = 8;

        System.out.println("8 >> 2 = " + (b >> 2)); // 8 ÷ 4 = 2

    }

}

```

 3.3 无符号右移(>>>):高位补 0,低位舍弃

无符号右移的规则是:将操作数的二进制位**向右移动指定位数**,低位舍弃,**无论正负,高位统一补 0**。此操作不保留符号位,因此仅适用于正数的逻辑右移(或对负数的位模式进行无符号处理)。

**原理示例**:计算 `-8 >>> 2`(以 32 位补码为例,仅展示低 8 位)

- `-8` 的 32 位补码:`11111111 11111111 11111111 11111000`

- 无符号右移 2 位后:`00111111 11111111 11111111 11111110`(即十进制 `1073741822`)

**代码示例**:

```java

public class UnsignedRightShiftDemo {

    public static void main(String[] args) {

        int a = -8;

        int result = a >>> 2;

        System.out.println("-8 >>> 2 = " + result); // 输出:1073741822

       

        int b = 8;

        System.out.println("8 >>> 2 = " + (b >>> 2)); // 8 ÷ 4 = 2(与普通右移结果一致)

    }

}

```

 3.4 移位运算的性能优势

移位运算由 CPU 直接支持,其执行速度远快于普通乘除运算。我们通过代码验证其性能差异:

```java

public class ShiftPerformanceDemo {

    public static void main(String[] args) {

        // 测试 2 × 16 与 2 << 4 的性能

        long start = System.nanoTime();

        System.out.println(2 * 16);

        long end = System.nanoTime();

        System.out.println("2 * 16 耗时:" + (end - start) + " 纳秒");

       

        long start1 = System.nanoTime();

        System.out.println(2 << 4);

        long end1 = System.nanoTime();

        System.out.println("2 << 4 耗时:" + (end1 - start1) + " 纳秒");

    }

}

```

**运行结果示例**:

```

32

2 * 16 耗时:231200 纳秒

32

2 << 4 耗时:15400 纳秒

```

可见,**移位运算的耗时仅为普通乘法的约 1/15**,在循环次数极多的场景下(如百万次、千万次运算),这种性能差异会直接影响程序效率。

 四、总结:运算符的选型与实践建议

4.1 结合运算符

- **适用场景**:所有需要“操作 + 赋值”的场景,优先使用结合运算符简化代码;

- **注意事项**:关注运算符优先级,复杂表达式需加括号明确逻辑。

 4.2 位运算

- **按位与(&)**:适合位掩码、清 0 操作;

- **按位或(|)**:适合置 1 操作、状态合并;

- **按位异或(^)**:适合交换变量、奇偶切换、简单加密;

- **注意事项**:位运算仅适用于整数类型,浮点数不支持位操作。

 4.3 移位运算

- **左移(<<)**:替代“乘以 2 的幂”,追求性能优先;

- **右移(>>)**:替代“除以 2 的幂”,保留符号位;

- **无符号右移(>>>)**:仅用于正数的逻辑右移或负数的无符号位模式处理;

- **注意事项**:移位位数若为负数或超过类型位数(如 int 移 32 位),行为未定义,需避免。

通过本文的学习,相信你已对 Java 中的结合运算符、位运算和移位运算有了全面的理解。在实际开发中,合理运用这些运算符不仅能让代码更简洁,还能显著提升程序性能,尤其在底层优化、算法设计等场景中,它们的价值将更加突出。建议在日常编码中多尝试这些运算符的实践,逐步培养对二进制位操作的敏感度,为解决更复杂的技术问题积累经验。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐