为什么这个语句不适用于java x ^ = y ^ = x ^ = y;

int x=1; int y=2; x ^= y ^= x ^= y; 

我期待值被交换。但它给出x = 0和y = 1。 当我尝试使用C语言时,它会给出正确的结果。

您的陈述大致相当于此扩展forms:

 x = x ^ (y = y ^ (x = x ^ y)); 

与C不同,在Java中,保证在右操作数之前计算二元运算符的左操作数。 评估如下:

 x = x ^ (y = y ^ (x = x ^ y)) x = 1 ^ (y = 2 ^ (x = 1 ^ 2)) x = 1 ^ (y = 2 ^ (x = 3)) x = 1 ^ (y = 2 ^ 3) // x is set to 3 x = 1 ^ (y = 1) x = 1 ^ 1 // y is set to 1 x = 0 // x is set to 0 

您可以反转每个xor表达式的参数顺序,以便在再次计算变量之前完成赋值:

 x = (y = (x = x ^ y) ^ y) ^ x x = (y = (x = 1 ^ 2) ^ y) ^ x x = (y = (x = 3) ^ y) ^ xx = (y = 3 ^ y) ^ x // x is set to 3 x = (y = 3 ^ 2) ^ x x = (y = 1) ^ x x = 1 ^ x // y is set to 1 x = 1 ^ 3 x = 2 // x is set to 2 

这是一个更紧凑的版本,也可以工作:

 x = (y ^= x ^= y) ^ x; 

但这是交换两个变量的真正可怕方式。 使用临时变量是一个更好的主意。

Mark对于如何在Java中进行评估是完全正确的。 原因是JLS§15.7.2。 ,在操作前评估操作数,以及§15.7 ,这需要从左到右进行评估:

它等同于(通过§15.26.2 ,复合赋值运算符):

 x = x ^ (y = y ^ (x = (x ^ y))); 

我们从左到右评估,在操作之前做两个操作数。

 x = 1 ^ (y = y ^ (x = (x ^ y))); // left of outer x = 1 ^ (y = 2 ^ (x = (x ^ y))); // left of middle x = 1 ^ (y = 2 ^ (x = (1 ^ y))); // left of inner x = 1 ^ (y = 2 ^ (x = (1 ^ 2))); // right of inner x = 1 ^ (y = 2 ^ (x = 3)); // inner xor (right inner assign) x = 1 ^ (y = 2 ^ 3); // inner assign (right middle xor) x = 1 ^ (y = 1); // middle xor (right middle assign) x = 1 ^ 1; // middle assign (right outer xor) x = 0; // outer xor (right outer assign) 

请注意,它在C中是未定义的行为,因为您在序列点之间修改了相同的变量两次。