1. 引言
先从一个生活类比开始。想象一个菜谱:
将面粉、鸡蛋和糖混合,搅打,加入黄油,再次搅打。
看起来有点奇怪吗?现在再想象一下,在“搅打”和“加入”之间加上逗号或括号。步骤立刻就清晰了。
在编程中,当你书写复杂表达式时,也会遇到类似的情况:
boolean result = a > 0 && b < 10 || c == 3;
计算顺序是什么?先计算:a > 0 && b < 10,然后再|| c == 3?还是相反?
如果没有明确的求值顺序,计算机可能会“把配料搞混”,结果就会出乎意料。
2. Java 中的运算符优先级
Java(与大多数编程语言一样)使用一张确定的运算符优先级表。
优先级更高的运算符会先于优先级更低的运算符执行。
来看这张表中最重要的部分(针对条件表达式):
| 运算符 | 说明 | 优先级 |
|---|---|---|
|
括号 | 最高 |
|
逻辑“非” | 较高 |
|
相等 / 不相等 | 中等 |
|
比较 | 中等 |
|
逻辑“与” | 较低 |
|
逻辑“或” | 更低 |
(还有算术运算符——它们的优先级高于逻辑运算符。)
关键规则
“与”(&&)的优先级高于“或”(||),
也就是说先计算“与”,再计算“或”。这并非巧合:“与”相当于逻辑乘法,而“或”相当于逻辑加法。
条件求值优先级的流程图
graph LR
A["a > 0"] --&&--> B["b < 10"]
B --||--> C["c == 3"]
(在实践中:a > 0 && b < 10 || c == 3——先计算 a > 0 && b < 10,然后再通过 || 把结果与 c == 3 组合。)
3. 运算符的方向:从左到右,还是相反
除了优先级,还有一个概念:结合性。
它规定了当同一优先级的运算符“相邻”出现时,按哪个方向进行求值。
示例:
boolean a = true, b = false, c = true;
boolean result = a && b && c;
问题:会如何计算?
答案:&& 的结合性是从左到右。
因此先计算 a && b,再把结果与 c 计算。
应用到条件表达式:
| 运算符 | 结合方向 |
|---|---|
|
从左到右 |
|
从右到左 |
4. 括号——处理复杂条件的最佳伙伴
这就是魔法(也是救星)开始的地方。当你编写表达式时,括号会改变优先级,并让代码更清晰、更安全。
示例 1(无括号):
// 我们的意图:“如果用户是成年人且是公民,或者他有特殊通行证”
boolean isAdult = age >= 18;
boolean isCitizen = country.equals("白俄罗斯");
boolean hasPermit = hasSpecialPass == true;
if (isAdult && isCitizen || hasPermit)
{
System.out.println("访问已允许!");
}
Java 的实际求值:
会先计算 isAdult && isCitizen,然后把结果与 hasPermit 通过 || 组合。
- 假设 isAdult = true,isCitizen = false,hasPermit = true
- isAdult && isCitizen → true && false → false
- false || true → true
也就是说,如果此人有特殊通行证,也会放行。
如果没有通行证,但既是成年人又是公民——同样会放行。
示例 2(带括号):
if (isAdult && (isCitizen || hasPermit))
{
System.out.println("访问已允许!");
}
现在程序会先检查:isCitizen || hasPermit,再把这个结果与 isAdult 一起计算。
也就是说,你必须是成年人,并且(要么是公民,要么拥有通行证)。
括号上的一点点差异,逻辑上的巨大不同!
GO TO FULL VERSION