Java里的运算符优先级如何理解_Java表达式计算顺序说明

Java运算符优先级不决定执行顺序,真正控制求值时机的是从左到右的操作数求值顺序、结合性及短路特性;例如method1()+method2()*method3()必先调用method1(),再method2(),最后method3()。

Java运算符优先级不是“从高到低依次执行”

很多人误以为只要记住优先级表,就能直接按顺序算表达式。其实不然:+* 的优先级差异确实决定 a + b * c 等价于 a + (b * c);但优先级不等于执行顺序,更不决定求值时机。真正控制“谁先算”的是结合性(left/right)和操作数求值顺序——Java明确规定:所有操作数从左到右依次求值,与运算符优先级无关。

比如:

method1() + method2() * method3()
,即使 * 优先级高于 +,也一定是先调用 method1(),再 method2(),最后 method3();乘法运算发生在三个方法都返回之后。

赋值类运算符(=+=等)的右结合性容易被忽略

=+=-= 等是右结合的,这意味着多个赋值连写时,从右往左解析:

  • a = b = c 等价于 a = (b = c),先执行 b = c(返回 c 的值),再赋给 a
  • a += b += c 等价于 a += (b += c)b += c 先完成并返回新值,再加到 a
  • c 是表达式(如 getCount()),它只被求值一次,且在最内层赋值前完成

常见陷阱:int a = 0, b = 0; a = b = 1 + 2; 中,1 + 2 只算一次,结果是 a == 3b == 3;但若写成 a = b = getCount();getCount() 也仅执行一次。

逻辑运算符 &&|| 的短路特性会跳过部分求值

它们优先级低于关系运算符(如 ==),但关键在于:一旦左操作数已能确定整个表达式结果,右操作数完全不求值

  • obj != null && obj.toString().length() > 0:如果 objnullobj.toString() 根本不会执行,避免空指针
  • isReady() || initialize():若 isReady() 返回 trueinitialize() 不会被调用
  • 注意:&|(位运算符)无短路行为,左右操作数总会求值,慎用于含副作用的表达式

短路不改变优先级——a d || e == f 仍按 >==&&

|| 分组,但求值过程可能提前终止。

自增/自减(++--)的位置影响值的使用时机

前置(++i)和后置(i++)不仅语法不同,语义上根本就是两个操作:前者返回递增后的值,后者返回递增前的副本。而这个“返回值”参与的是整个表达式的计算,不是最终赋值目标。

  • int i = 1; int j = i++ + ++i;:执行顺序是 —— 取 i 当前值(1)用于加法左操作数,然后 i 变为 2;接着 ++ii 变为 3 并返回 3;最终 j = 1 + 3 == 4i == 3
  • 不要依赖多处修改同一变量的复合表达式,JLS 明确说明其行为由求值顺序保证,但可读性差、易出错
  • 编译器不会重排这类表达式;Java 严格按从左到右求操作数、再按优先级和结合性执行运算

真正复杂的地方不在优先级表本身,而在「操作数求值」和「运算执行」这两个阶段的分离——多数 bug 出现在混淆了这两者。