首页 > 代码库 > Java随笔:使用异或操作交换变量值的风险

Java随笔:使用异或操作交换变量值的风险

在面试中,经常会问到“如何不用中间变量交换两个变量值”。

看看下面这个代码输出是什么:

int x = 1984;int y = 2001;x^=y^=x^=y;System.out.println("x="+x+";y="+y);

看上去应该很完美的:x=2001;y=1984

实际输出是:x=0;y=1984

问题出在哪里?是的,就是JVM的编译器。

看看实际的汇编:

   Code:      0: sipush        1984      3: istore_1      4: sipush        2001      7: istore_2      8: iload_1      9: iload_2     10: iload_1     11: iload_2     12: ixor     13: dup     14: istore_1     15: ixor     16: dup     17: istore_2     18: ixor     19: istore_1     20: getstatic     #2

这里并没有按照我们想象中的顺序:

  1. x^=y
  2. y^=x^=y
  3. x^=y^=x^=y

而是这样的顺序:

  1. x=1984
  2. y=2001
  3. temp1=x
  4. temp2=y
  5. temp3=x^y
  6. x=temp3
  7. y=temp2^temp3
  8. x=temp1^y

让我们为汇编对应进行一下注释:

   Code:      0: sipush        1984      3: istore_1 // x=1984      4: sipush        2001      7: istore_2 // y=2001      8: iload_1 // 堆栈(高到低) 1984      9: iload_2 // 2001, 1984     10: iload_1 // 1984,2001,1984     11: iload_2 // 2001,1984,2001,1984     12: ixor // 2001^1984 ,堆栈(17,2001,1984)     13: dup // temp3=2001^1984=17     14: istore_1 // x=temp3=17     15: ixor // 17^2001,堆栈(1984,,1984)     16: dup // temp3=1984     17: istore_2 // y=1984     18: ixor  // 1984^1984,堆栈(0)     19: istore_1 // x=0     20: getstatic     #2

 也就是说,实际编译器没有按照我们想象的那样,执行x^=y^=x^=y。

总结

单个表达式不要对相同的变量赋值2次,否则无法从混乱中得到预期的结果。

使用异或进行数值交换,容易产生bug,不易读且难以维护。

 

Java随笔:使用异或操作交换变量值的风险