【发布时间】:2019-05-13 23:03:17
【问题描述】:
考虑以下示例:
class Quirky {
public static void main(String[] args) {
int x = 1;
int y = 3;
System.out.println(x == (x = y)); // false
x = 1; // reset
System.out.println((x = y) == x); // true
}
}
我不确定 Java 语言规范中是否有一项规定加载变量的前一个值以与右侧 (x = y) 进行比较,按照括号中暗示的顺序,应该计算首先。
为什么第一个表达式的计算结果为false,而第二个表达式的计算结果为true?我本来希望首先评估 (x = y),然后它将 x 与自身 (3) 进行比较并返回 true。
这个问题与order of evaluation of subexpressions in a Java expression 不同,x 在这里绝对不是“子表达式”。它需要加载进行比较,而不是“评估”。这个问题是特定于 Java 的,表达式 x == (x = y) 不同于通常为棘手的面试问题而设计的牵强附会的不切实际的结构,它来自一个真实的项目。它应该是比较和替换习语的单行替换
int oldX = x;
x = y;
return oldX == y;
它比 x86 CMPXCHG 指令更简单,应该在 Java 中使用更短的表达式。
【问题讨论】:
-
左手边总是在右手边之前被评估。括号对此没有影响。
-
评估表达式
x = y肯定是相关的,并导致将x设置为y的值的副作用。 -
帮自己和队友一个忙,不要将状态突变与状态检查混为一谈。这样做会大大降低代码的可读性。 (在某些情况下,由于原子性要求,它是绝对必要的,但那些功能已经存在并且它们的目的将立即被识别。)
-
真正的问题是你为什么要写这样的代码。
-
您问题的关键是您错误地认为括号意味着评估顺序。这是一个普遍的信念,因为我们在小学的数学教学方式以及一些初学者编程书籍仍然会出错,但这是一个错误的信念。这是一个非常常见的问题。您可能会从阅读我关于该主题的文章中受益;它们是关于 C# 但它们适用于 Java:ericlippert.com/2008/05/23/precedence-vs-associativity-vs-orderericlippert.com/2009/08/10/precedence-vs-order-redux
标签: java variable-assignment equality operator-precedence jls