Java 运算符与表达式:那些反直觉的点
更新时间:2026-09-20。基本类型体系见 基本类型与包装类,
i++在多线程下的问题见 volatile 能保证原子性吗。本篇只讲运算符层面最容易写错的地方。
一、整数除法与取余
java
System.out.println(7 / 2); // 3,不是 3.5:两个 int 相除结果还是 int,直接截断
System.out.println(7 / 2.0); // 3.5:有一边是 double 才做浮点除法
System.out.println(-7 / 2); // -3(向 0 截断)
System.out.println(7 % 3); // 1
System.out.println(-7 % 3); // -1:Java 的 % 结果符号跟被除数,可能为负想保留小数:(double) a / b,注意强转只作用于紧接的 a,要在除法之前转。
二、自增自减与赋值表达式
java
int x = 5;
int y = x++; // y=5, x=6:后缀先用旧值再 +1
int z = ++x; // x=8, z=8:前缀先 +1 再用新值
int a, b;
a = b = 10; // 合法:赋值表达式有值,从右向左结合;a、b 都 10i++ 是「读—加—写」三步,不是原子操作,多线程共享变量必须用原子类或加锁。
三、逻辑运算的短路 vs 非短路
| 运算 | 含义 | 短路? |
|---|---|---|
&& | 逻辑与 | ✅ 左为 false 就不算右边 |
|| | 逻辑或 | ✅ 左为 true 就不算右边 |
& / | | 按位与/或(对 boolean 是非短路逻辑) | ❌ 两边都算 |
java
if (s != null && s.length() > 0) { ... } // 依赖短路防空指针
boolean r = sideEffect1() | sideEffect2(); // 两边都执行(少用)短路既能防空指针,也可能「跳过」带副作用的方法,排查时别漏。
四、== 比的是什么
- 对基本类型比值;
- 对引用类型比的是对象地址(是不是同一个对象),不是内容。字符串/包装类内容比较一律用
.equals,常量池例外见 String 常量池与 intern。
java
new String("a") == new String("a"); // false,两个对象
Integer i1 = 127, i2 = 127; // true(缓存)
Integer i3 = 200, i4 = 200; // false!超出 -128~127 缓存,见自动装箱篇五、位运算与掩码
java
int flags = 0b1010;
flags & 0b0100 // 取某位:0 表示该位没置
flags | 0b0100 // 置位(变成 1110)
flags & ~0b1000 // 清位
flags ^ 0b1111 // 翻转低 4 位
flags << 2 // 左移 2 位 ≈ 乘 4(注意溢出)
flags >>> 1 // 无符号右移,高位补 0;>> 是算术右移补符号位
>>>与>>的区别是高频点:负数用>>仍为负(补 1),>>>恒补 0。位图、权限标记、哈希扰动常用这些操作。
六、类型提升与强制转换
混合运算时小类型会被提升:byte/short/char 在表达式里至少提升成 int,所以
java
byte b1 = 1, b2 = 2;
byte b3 = b1 + b2; // 编译错误:结果是 int
byte b3 = (byte)(b1 + b2); // 必须强转
long l = 100_000_000_000; // 编译错误:整数字面量默认 int,超范围
long l = 100_000_000_000L; // 加 L
double d = 5 / 2; // d=2.0!先按 int 算出 2 再转,不是 2.5强转可能丢精度/溢出:(int) 3.9 得 3,(byte) 130 得 -126。
七、浮点不要直接 ==
java
0.1 + 0.2 == 0.3 // false(二进制浮点无法精确表示)
Math.abs(a - b) < 1e-9 // 用误差范围比较需要精确十进制金额用 BigDecimal(且用字符串构造)。
总结
Java 表达式最易踩的坑是:int/int 截断成 int、% 结果可能为负;x++/++x 前缀后缀差在返回旧值还是新值且自增非原子;&&/|| 短路可防空指针但会跳过副作用;== 对引用只比地址、内容用 equals;>>> 补 0、>> 补符号位;混合运算 byte/short/char 提升为 int 导致赋值要强转、整数字面量默认 int 超长要加 L、double d=5/2 仍得 2.0;浮点有误差要按区间比较。