根据Java 规范(Java 7 规范)第 15.26.2 节(第 529 页)。
形式的复合赋值表达式E1 op= E2
等价于E1 = (T) ((E1) op (E2))
,其中T
是 的类型E1
,除了E1
只计算一次。
根据第 15.7 节评估顺序(第 423 页)(强调我的):
15.7 评估顺序
Java 编程语言保证运算符的操作数看起来是以特定的评估顺序进行评估的,即从左到右。
15.7.1 先计算左手操作数
在评估右侧操作数的任何部分之前,二元运算符的左侧操作数似乎已被完全评估。
如果运算符是复合赋值运算符(第 15.26.2 节),则左侧操作数的评估包括记住左侧操作数表示的变量以及获取和保存该变量的值以用于隐含的二元运算.
如果二元运算符的左侧操作数的求值突然完成,则右侧操作数的任何部分似乎都没有被求值。
在第 15.26.2 节(第 529 页)中有更详细的描述:
如果左侧操作数表达式不是数组访问表达式,则:
• 首先,评估左侧操作数以产生变量。[修剪]
• 否则,将保存左侧操作数的值,然后计算右侧操作数。[修剪]
• 否则,左侧变量的保存值和右侧操作数的值用于执行复合赋值运算符指示的二元运算。[修剪]
• 否则,二元运算的结果将转换为左侧变量的类型,经过值集转换(第 5.1.13 节)到适当的标准值集(不是扩展指数值集),并且转换结果存储到变量中。
文档中的示例
示例 15.26.2-2。复合赋值左侧的值在评估右侧之前保存
class Test {
public static void main(String[] args) {
int k = 1;
int[] a = { 1 };
k += (k = 4) * (k + 2);
a[0] += (a[0] = 4) * (a[0] + 2);
System.out.println("k==" + k + " and a[0]==" + a[0]);
}
}
所以问题中的表达式被重写并分组为:
i = i ^ (j = j ^ (i = i ^ j));
评估左操作数:
i = 24 ^ (j = 17 ^ (i = 24 ^ 17));
**
由于 的值没有像预期的那样“更新”,所以当被交换到时i
,它会导致 的值i
变为 0 。24
j