前言
学运算符。我以为和 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、高效计算),前端几乎不用。我画了一张表帮助记忆:
常见应用场景
- 权限控制: 用不同位表示不同权限
- 状态标记: 一个整数存储多个布尔值
- 性能优化: 位运算比算术运算快
- 加密算法: 数据混淆和变换
- 硬件操作: 直接控制寄存器位
今日耗时与感受
- 学习时间:2.5 小时
- 最大坑:整数除法截断(惯性思维害死人)
- 最大收获:理解了 StringBuilder 的存在意义,以及位运算的实际应用场景