为什么这个语句在java中不起作用 x ^= y ^= x ^= y;
2022-09-03 16:21:18
int x=1;
int y=2;
x ^= y ^= x ^= y;
我期望交换这些值。但它给出 x=0 和 y=1。当我尝试使用C语言时,它给出了正确的结果。
int x=1;
int y=2;
x ^= y ^= x ^= y;
我期望交换这些值。但它给出 x=0 和 y=1。当我尝试使用C语言时,它给出了正确的结果。
您的语句大致等效于此展开形式:
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) ^ x
x = (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 中,这是未定义的行为,因为您在序列点之间修改同一变量两次。