Java 中方法调用和参数之间的计算顺序

Evaluation order between a method call and arguments in Java

提问人:Amessihel 提问时间:1/3/2020 最后编辑:user207421Amessihel 更新时间:1/3/2020 访问量:440

问:

在处理另一个 SO 问题时,我想知道下面的代码是否有未定义的行为:

if (str.equals(str = getAnotherString())) {
  // [...]
}

我倾向于认为,在作为参数传递的进一步赋值之前,会评估进行调用的引用。有关于它的来源吗?strequals()str

java undefined-behavior 赋值-运算符 评估 方法-调用

评论

0赞 Sweeper 1/3/2020
绝对不会是未定义的行为。Java 很少这样的。
0赞 Kaan 1/3/2020
您发布的代码是定义的行为。答案在 JLS 中,可能低于 15.7
0赞 alainlompo 1/3/2020
你虽然是对的。因为如果首先计算,则整个表达式将始终为真。str = ...
0赞 user207421 1/3/2020
计算顺序与运算符优先级不同。
0赞 bananas 1/3/2020
在这种情况下,请注意NPE

答:

2赞 Sweeper 1/3/2020 #1

这在 JLS 第 15.12.4 节中明确规定:

在运行时,方法调用需要五个步骤。首先,可以计算目标参考。其次,计算参数表达式。[...]

你问的“目标参考”是什么?这在下一小节中指定:

15.12.4.1. 计算目标参考(如有必要)

...

  • 如果 form 为 ExpressionName 。[类型参数]标识符,则:
    • 如果调用模式是静态的,则没有目标引用。计算 ExpressionName,但随后丢弃结果。
    • 否则,目标引用是 ExpressionName 表示的值。

因此,“目标引用”是 in 中的位 - 您调用该方法的表达式。strstr.equals

正如第一个引号所说,首先计算目标引用,然后计算参数。因此,仅当返回的字符串与赋值表达式之前的字符相同时,计算结果才为 true。str.equals(str = getAnotherString())getAnotherStringstr

所以,是的,你倾向于认为是正确的。但这不是“未定义的行为”。