Java 表达式顺序、运算符优先级和关联性之间的区别

Posted

技术标签:

【中文标题】Java 表达式顺序、运算符优先级和关联性之间的区别【英文标题】:Differences between Java order of expression, operator precedence and associativity 【发布时间】:2020-12-03 21:17:24 【问题描述】:

我在考试中遇到了这个问题。

考题:以下代码sn-p的结果是什么?

3: var tiger = "Tiger";
4: var lion = "Lion";
5: final var statement = 250 > 338 ? lion : tiger = " is Bigger";
6: System.out.println(statement);

正确答案是

F。由于第 5 行,代码将无法编译

解释是:

    代码无法编译,因为赋值运算符在此表达式中具有最高优先级。 三元运算符的两边必须具有相同的类型。这个表达式无效,作为左边第二个赋值 运算符不是变量,所以答案是选项 F。 请注意,如果问题在表达式周围添加了明确的括号(Tiger = " is Bigger"),则选项 E 将具有正确的 输出。

当我自己运行代码时,出现编译错误:

test.java:11: error: unexpected type
final var statement = 250 > 338 ? lion : tiger = " is Bigger";
                                ^
  required: variable
  found:    value
1 error
error: compilation failed

在征求第二意见后,阅读 JLS 部分15,以及这些其他 SO 问题:

What are the rules for evaluation order in Java?

If parenthesis has a higher precedence then why is increment operator solved first?

我想出了几个理论:

    表达式求值顺序、运算符优先级和关联性是不同的概念。 根据 JLS 15.7.3,表达式评估尊重括号和运算符优先级。 所有表达式的计算都是从左到右进行的。 运算符优先级决定了表达式的分组。 关联性仅适用于同一运算符,并确定使用同一运算符的表达式的执行顺序。 Java 在编译时检查有效表达式,从左到右,尊重括号和运算符优先级。 对于带有运算符的表达式,它会根据运算符以不同的方式对操作数执行此检查。

有了新知识,我现在试着解释一下为什么第 5 行编译失败:

    Java 开始检查有效表达式,使用表达式求值顺序,从左到右。 Java 找到第一个赋值运算符(最左边)。 由于赋值运算符“=”具有从右到左的关联性,Java 检查右侧是否有任何其他赋值运算符并开始计算更右的赋值运算符。 它找到一个“=”,然后检查右侧的任何其他“=”。 我没有找到其他“=”,因此它开始计算最右边“=”的操作数。 根据 15.26,Java 会检查前一个“=”和这个“=”之间的所有内容是否只是一个变量。 它找到表达式250 > 338 ? lion : tiger,这是一个有效的表达式,但这个表达式的计算结果是一个值。 Java 只允许赋值运算符左侧的变量,所以编译失败。

现在我将尝试应用同样的理论来解释这段代码的正确场景:final var statement = 250 > 338 ? lion : (tiger = " is Bigger");

    Java 开始检查有效表达式,使用表达式求值顺序,从左到右。 Java 在同一“作用域”中找不到任何其他赋值运算符“=”。 根据 15.26,Java 检查此“=”的左操作数是否为变量。通过。 然后它评估右操作数是否是返回可分配给左操作数的值的有效表达式。

考试提供的解释是否落空了,还是我仍然不明白这段代码是怎么编译不出来的?

    他们表示赋值运算符“=”在此表达式中具有最高优先级。根据此运算符优先级表http://www.cs.bilkent.edu.tr/~guvenir/courses/CS101/op_precedence.html,赋值运算符的优先级最低。 他们将运算符优先级与求值表达式的顺序互换使用,而不是将这两个概念分开?

【问题讨论】:

求值顺序是指表达式的操作数被求值的顺序(例如一系列函数调用),在Java中它是严格从左到右的。和这个问题没有任何关系。 【参考方案1】:

你是对的,他们说错了,赋值运算符的优先级最低

你错了,他们从来没有在任何地方提到“评估的顺序”(无论如何你已经展示过)。显示的代码在评估顺序很重要的地方没有做任何事情。分配与评估顺序无关。



    代码无法编译,因为赋值运算符在此表达式中具有最高优先级。

Operator precedence 显示:

9   >   relational
2   ?:  ternary
1   =   assignment

这意味着要使用括号显式显示优先级,语句变为:

statement = ((250 > 338) ? lion : tiger) = " is Bigger";

    三元运算符的两边必须具有相同的类型。这个表达式无效,因为第二个赋值运算符的左边不是变量,所以答案是选项F。

三元运算符为((250 > 338) ? lion : tiger),“双方”指的是两个赋值运算符。

正如它所说,“这个表达式无效,因为第二个赋值运算符的左侧不是变量”。


    请注意,如果问题在表达式周围添加了显式括号(Tiger = " is Bigger"),则选项 E 将具有正确的输出。

你自己已经确认过了。

要使用括号显式显示优先级,语句变为:

statement = ( (250 > 338) ? lion : (tiger = " is Bigger") );

【讨论】:

以上是关于Java 表达式顺序、运算符优先级和关联性之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

带括号的逻辑运算的优先顺序(Java)[重复]

JavaScript中运算符的优先级

Java表达式的执行顺序

循环条件中的三元运算符:评估顺序/操作。优先级不明确

Java语言常用的运算符和表达式详解

c语言中关系运算符和自加自减运算优先级哪个高