为什么这个语句在javax^=y^=x^=y中不起作用;
我希望这些值可以交换,但它给出了x=0和y=1。为什么这个语句在javax^=y^=x^=y中不起作用;,java,swap,undefined-behavior,xor,Java,Swap,Undefined Behavior,Xor,我希望这些值可以交换,但它给出了x=0和y=1。 当我尝试使用C语言时,它给出了正确的结果。您的语句大致相当于此扩展形式: int x=1; int y=2; x ^= y ^= x ^= y; 与C语言不同,在Java中,二元运算符的左操作数保证在右操作数之前求值。评估过程如下: x = x ^ (y = y ^ (x = x ^ y)); 可以反转每个xor表达式的参数顺序,以便在再次计算变量之前完成赋值: x = x ^ (y = y ^ (x = x ^ y)) x = 1 ^ (y
当我尝试使用C语言时,它给出了正确的结果。您的语句大致相当于此扩展形式:
int x=1;
int y=2;
x ^= y ^= x ^= y;
与C语言不同,在Java中,二元运算符的左操作数保证在右操作数之前求值。评估过程如下:
x = x ^ (y = y ^ (x = x ^ y));
可以反转每个xor表达式的参数顺序,以便在再次计算变量之前完成赋值:
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
这是一个更紧凑的版本,也适用于:
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
但这是一种真正可怕的交换两个变量的方式。使用临时变量是一个更好的主意。Mark完全正确地描述了它在Java中的计算方式。原因是JLS,在操作之前对操作数求值,并且需要从左到右求值: 它(通过复合赋值运算符)等效于: 我们从左到右求值,在运算之前执行两个操作数
x = x ^ (y = y ^ (x = (x ^ y)));
请注意,这在C中是未定义的行为,因为在序列点之间修改同一变量两次。在C中是未定义的行为,因为在序列点中修改x和y两次。不要使用它。使用额外的temp变量交换2更有效,因为它不必进行计算你完全错了。仅仅因为“计算”对我们人类来说需要更长的时间,没有理由认为它需要比计算机上的一次分配更长的时间。事实上,我打赌这两种方法都需要同样长的时间。XOR是CPU能做的最简单的操作。“正确”这个词不正确。你确定吗?我认为赋值返回true,这就是为什么使用了where=而不是始终运行==的if语句?这意味着你的第一句话与x=x^true^true相同@Aaron,no.JLS:“在运行时,赋值表达式的结果是赋值发生后变量的值。”在Java中,只有当变量是布尔值时,才会编译
=
而不是if
条件中的=
。
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)