为什么“a^=b^=a^=b;”与“a^=b;”不同;b^=a;a^=b;“?

我尝试了一些代码来交换Java中的两个整数,而不使用第三个变量,使用XOR。

以下是我尝试过的两个交换函数:

package lang.numeric;

public class SwapVarsDemo {

    public static void main(String[] args) {
        int a = 2984;
        int b = 87593;
        swapDemo1(a,b);
        swapDemo2(a,b);
    }

    private static void swapDemo1(int a, int b) {
        a^=b^=a^=b;
        System.out.println("After swap: "+a+","+b);
    }

    private static void swapDemo2(int a, int b) {
        a^=b;
        b^=a;
        a^=b;
        System.out.println("After swap: "+a+","+b);
    }

}

此代码生成的输出是这样的:

After swap: 0,2984
After swap: 87593,2984

我很好奇,为什么会有这样的说法:

        a^=b^=a^=b;

和这个不一样?

        a^=b;
        b^=a;
        a^=b;

答案 1

问题在于评估的顺序:

请参阅 JLS 第 15.26.2 节

首先,计算左侧操作数以生成变量。如果此计算突然完成,则赋值表达式由于同样的原因突然完成;不计算右侧操作数,并且不会进行赋值。

否则,将保存左侧操作数的值,然后计算右侧操作数。如果此计算突然完成,则赋值表达式由于同样的原因突然完成,并且不会发生赋值。

否则,左侧变量的保存值和右侧操作数的值将用于执行复合赋值运算符指示的二元运算。如果此操作突然完成,则赋值表达式会出于同样的原因突然完成,并且不会发生赋值。

否则,二进制运算的结果将转换为左侧变量的类型,并经过值集转换 (§5.1.13) 到适当的标准值集(不是扩展指数值集),转换结果将存储到变量中。

因此,您的表达式可以:

a^=b^=a^=b;

  1. 评价a
  2. 评价b^=a^=b
  3. 或两者(因此步骤一中尚未应用于它)a^=b
  4. 将结果存储在a

换句话说,您的表达式等效于以下 java 代码:

    int a1 = a;
    int b2 = b;
    int a3 = a;
    a = a3 ^ b;
    b = b2 ^ a;
    a = a1 ^ b;

从方法的已反汇编版本中可以看出:

  private static void swapDemo1(int, int);
    Code:
       0: iload_0       
       1: iload_1       
       2: iload_0       
       3: iload_1       
       4: ixor          
       5: dup           
       6: istore_0      
       7: ixor          
       8: dup           
       9: istore_1      
      10: ixor          
      11: istore_0  

答案 2

因为被解析为:a ^= b ^= a ^= b;

a ^= (b ^= (a ^= b));

这可以简化为:

a ^= (b ^= (a ^ b));

所以会有价值,最后会是。bb ^ (a ^ b)aa ^ (b ^ (a ^ b)


推荐