这里混合了两种不同的东西:表达式解析和表达式求值。
让我们从表达式开始:++a + ++a * ++a
。我们首先与它有什么关系?由于运算符+
and*
需要两个操作数并且++
需要一个,我们必须弄清楚哪个操作数与哪个操作一起使用。这是表达式解析步骤,其中应用了优先级/关联性。
++
具有最高优先级,因此我们可以将表达式重写为(++a) + (++a) * (++a)
- 接下来是
*
,所以我们可以再次添加括号:(++a) + ((++a) * (++a))
- 最后我们有
+
,是所有优先级中最低的,所以为了对称,我们可以这样写: ((++a) + ((++a) * (++a)))
请注意,我们可以将其巧妙地表示为一棵树:
+
/ \
++ *
| | \
a ++ ++
| |
a a
所以这是我们基于优先级和关联性的评估树。
请注意,在这种情况下,关联性根本不重要,因为所有运算符都有不同的优先级。如果我们的表达式是4 - 1 - 3 + 2
,那么使用关联性来达到(((4 - 1) - 3) + 2)
、+
和-
具有相同的优先级就很重要了。
现在是下一步,评估。评估总是从左到右进行(即使对于分配,虽然规则有点古怪),但它使用我们刚刚构建的树从左到右进行。
- 所以首先我们开始评估
+
运算符,因为它在顶部。
- 然后我们向左下一层,因为我们评估运算符
++a
左侧的+
,(6)
- 然后我们向右走并开始评估
*
操作。
- 我们这样做的方式是评估第二个
++a
, (7)
- 然后是第三个
++a
(8)
- 然后我们将第 4 步和第 5 步的结果相乘(这是
*
评估的操作),(56)
- 最后我们将第 6 步的结果与第 2 步的结果相加(62)
......我们完成了。
TL;DR:优先级和关联性决定了括号的放置位置,但评估始终是从左到右的。
15.7. 评估令
Java 编程语言保证运算符的操作数看起来是以特定的评估顺序进行评估的,即从左到右。