运算符优先级是Java基础中最容易被轻视的知识点。不少开发者觉得表达式写出来IDE能编译通过就没问题,可实际情况是,优先级理解不到位导致的bug往往能编译、能运行,只是结果悄悄错了。比如a & b == c这样的式子,很多人以为先算位与,实际却先算比较。这篇文章把优先级规则和括号使用方法讲透,帮你彻底避开这类陷阱。

Java运算符优先级的完整层次
Java中的运算符按优先级从高到低大致可以分为十几层,最顶层的包括后缀形式的a++、a--,以及一元运算符++a、--a、!a、~a、-a。往下一层是乘除取模,再往下是加减,然后是位移运算符<<、>>、>>>,接着是关系运算符<、>、instanceof、==、!=,之后才是按位与&、按位异或^、按位或|,再往下是逻辑与&&、逻辑或||,最后是三元运算符和赋值运算符。
这里有一个非常经典的坑:&的优先级低于==。也就是说a & b == c会被解析成a & (b == c),而不是(a & b) == c。写位运算标志位判断的同学稍不留神就会踩进去。同样,a | b ^ c会先算异或再算或,因为^的优先级高于|。
可以用下面这段代码验证优先级的效果:
public class PriorityDemo {
public static void main(String[] args) {
int a = 6; // 二进制 110
int b = 3; // 二进制 011
int c = 2;
// 很多人以为是 (a & b) == 2,结果是 true
// 实际是 a & (b == 2),即 6 & (3 == 2)
// b == 2 为 false,转成 int 是 0,结果为 0
// 注意:Java 中布尔值不能直接参与位运算,这里会编译报错
// 正确写法应当明确加括号
boolean result = (a & b) == 2;
System.out.println(result); // true
// 位移优先级低于加减
System.out.println(1 << 2 + 3); // 等价于 1 << 5,输出 32
System.out.println((1 << 2) + 3); // 输出 7
}
}
除了优先级,还有一个概念叫结合性。同一优先级的运算符按结合方向求值:大部分二元运算符是左结合,比如a - b - c等价于(a - b) - c;而赋值运算符和三元运算符是右结合,a = b = c等价于a = (b = c)。理解结合性能帮你解释那些括号看起来很奇怪却编译通过的代码。
最容易写错的几个典型场景
场景一:自增自减参与表达式
i++和++i在表达式中的行为差别是面试和实际编码的双重高频考点。看下面的例子:
int i = 5; int result = i++ + ++i; // 过程:i++ 取 5,i 变 6;++i 先加 1 变 7,取 7 // result = 5 + 7 = 12 System.out.println(result); // 12 System.out.println(i); // 7
这种代码虽然能考察你对求值顺序的理解,但在实际项目中绝对不要这么写。一行表达式里出现多个自增运算符,code review时几乎一定会被打回。正确做法是把自增拆到单独的语句里,让每一步的变化都清晰可见。
场景二:三元运算符嵌套
三元运算符是右结合的,嵌套时非常容易看错层级:
int score = 85; // 右结合:score >= 90 ? "A" : (score >= 80 ? "B" : "C") String grade = score >= 90 ? "A" : score >= 80 ? "B" : "C"; System.out.println(grade); // B
虽然编译器解析没有歧义,但阅读者需要靠记忆右结合规则才能理清结构。两层以上的嵌套建议改用if-else或者显式括号,不要为了省几行代码牺牲可读性。
场景三:逻辑与位与混用
权限校验代码里常见flags & WRITE != 0这种写法,由于!=优先级高于&,实际执行的是flags & (WRITE != 0),在Java中会直接编译报错(int不能和boolean做位运算),这反而是件好事,强制你发现错误。但如果是&&和比较运算混用就没这么幸运了,逻辑错误能安静地通过编译。
括号的正确使用姿势
解决优先级混乱最直接的手段就是加括号,但括号也不是越多越好。基本原则是:涉及位运算、位移、逻辑运算混合的表达式必须加括号;涉及优先级相近但语义容易误判的组合建议加括号;而a + b * c这种小学数学就教的规则,加括号写成a + (b * c)反而是画蛇添足,暴露出对基础语法的不自信。
还有一个实用技巧:短路逻辑&&和||与赋值或方法调用组合时,加括号能明确表达意图。比如flag = a == b || c > d;虽然优先级上没有问题,但写成flag = (a == b) || (c > d);可读性明显更好。括号在这里的作用不是修正运算顺序,而是降低读者的心智负担。
团队协作中建议把括号规范写进代码风格文档:复合布尔条件必须用括号分组、位运算必须加括号、超过两个运算符的表达式优先考虑拆分变量。例如:
// 反例:一行塞太多逻辑 boolean ok = list != null && !list.isEmpty() && list.get(0) > 0 || debug; // 正例:拆分中间变量,意图一目了然 boolean hasValidItem = list != null && !list.isEmpty() && list.get(0) > 0; boolean ok = hasValidItem || debug;
最后提一句工具层面的保障。开启IDE的静态检查,IntelliJ IDEA会对可疑的优先级组合给出提示;SonarLint等插件也能识别出过度复杂的表达式。与其靠人肉记忆十几层优先级表,不如让工具帮你兜底,人的精力留给设计清晰的代码结构。
总结一下,Java运算优先级的核心记忆点是:算术高于关系,关系高于位运算,位运算高于逻辑,赋值和三元垫底。位运算和位移是最大的雷区,遇到它们就条件反射地加括号。括号用在对的地方,代码的正确性和可读性会同时提升。
Java运算符优先级运算顺序括号使用修改时间:2026-09-16 06:20:34