Java Puzzle读书笔记(3):使用异或操作交换变量值的风险

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

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

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)