Java 运算符:8年前端踩了 5 个和 JS 不一样的坑

0 阅读3分钟

前言

学运算符。我以为和 JS 一样,结果踩了好几个坑。这篇记录我的踩坑实录。


坑 1:整数除法截断

int a = 5;
int b = 2;
System.out.println(a / b);  // 输出 2,不是 2.5!

JS 里 5 / 2 = 2.5,Java 里 int / int = int,小数直接砍掉。要得到小数,必须转类型:

System.out.println((double)a / b);  // 2.5

坑 2:整数溢出

int max = Integer.MAX_VALUE;  // 2147483647
System.out.println(max + 1);  // -2147483648

Java 不会报错,直接变成负数。这比 JS 的 Infinity 危险多了。

坑 3:++i 和 i++ 的面试题

int m = 1;
int n = m++ + ++m + m++;
// 结果 n = 7, m = 4

和 JS 规则一样,但 Java 面试更爱考。我的记忆法:前置先加再取,后置先取再加

坑 4:短路逻辑的实际影响

int x = 5;
boolean result = (x < 3) && (++x > 10);
// x 还是 5!++x 没执行

短路特性虽然和 JS 一样,但在 Java 里结合副作用操作(++)时,更容易出 bug。

坑 5:字符串拼接的顺序

System.out.println("sum = " + 10 + 20);   // "sum = 1020"
System.out.println("sum = " + (10 + 20));  // "sum = 30"

字符串 + 的优先级从左到右,和 JS 一样,但 Java 里更常用来拼接 SQL/日志,坑更明显。

新发现:StringBuilder

StringBuilder sb = new StringBuilder();
sb.append("Hello").append(" ").append("Java");
System.out.println(sb.toString()) // "Hello Java"

Java 的 String 不可变,频繁拼接要用 StringBuilder。这在前端完全没有对应概念(JS 字符串是可变的)。

位运算:前端完全陌生的领域

int a = 5;   // 二进制: 0000 0101
int b = 3;   // 二进制: 0000 0011

// 按位与:两个位都为 1 时,结果才为 1
System.out.println("a & b = " + (a & b));   // 1  (0000 0001)
// 按位或:两个位中只要有一个为 1,结果就为 1
System.out.println("a | b = " + (a | b));   // 7  (0000 0111)
// 按位异或:两个位不同时结果为 1,相同时为 0
System.out.println("a ^ b = " + (a ^ b));   // 6  (0000 0110)
// 按位取反:0 变 1,1 变 0
System.out.println("~a = " + (~a));         // 1010 (在补码表示中实际为 -6)

// 移位运算(高效乘除法)
// 左移:所有位向左移动指定位数,右边补 0
System.out.println("a << 1 = " + (a << 1));  // 10 (5 * 2)(0000 1010)
System.out.println("a << 2 = " + (a << 2));  // 20 (5 * 4)(0000 0100)
// 右移:所有位向右移动指定位数,左边补符号位(正数补 0,负数补 1)
System.out.println("a >> 1 = " + (a >> 1));  // 2  (5 / 2) (0000 0010)

// 无符号右移:也叫逻辑右移(无论正负数,左边都补 0)
int c = 20;  // 二进制: 0001 0100
System.out.println("c >> 2 = " + (c >> c));    // 5 (0000 0101)等价于 20 / 4
int d = -20  // 二进制: (补码表示):11111111 11111111 11111111 11101100
// 右移2位,左边补 0(注意不是补 1)
//         ↓↓
// 结果:  00111111 11111111 11111111 11111011  (很大的正数)
System.out.println("d >>> 2 = " + (d >>> 2));  // 输出:1073741819

运算过程
1.以 a & b 为例:
2.将十进制数转换为二进制
3.对齐两个数的每一位
4.对每一位执行逻辑与运算
5.将结果转换回十进制

位运算在 Java 里很常见(权限、HashMap、高效计算),前端几乎不用。我画了一张表帮助记忆:

图片.png

常见应用场景

  • 权限控制: 用不同位表示不同权限
  • 状态标记: 一个整数存储多个布尔值
  • 性能优化: 位运算比算术运算快
  • 加密算法: 数据混淆和变换
  • 硬件操作: 直接控制寄存器位

今日耗时与感受

  • 学习时间:2.5 小时
  • 最大坑:整数除法截断(惯性思维害死人)
  • 最大收获:理解了 StringBuilder 的存在意义,以及位运算的实际应用场景