您的位置:首页 > 编程语言 > Java开发

java解惑之表达式之谜(谜题7)

2015-01-01 20:05 148 查看
谜题7:互换内容
下面这个程序使用了复合的异或赋值操作符,它展示的技术师一种编程习俗,那么它会打印什么呢?
public class CleverSwap{
public static void main(String[] args){
int x = 1984; //0x7c0
int y = 2001; //0x7d1
x^=y^=x^=y;
System.out.println("x=" + x + "; y=" + y);
}
}
很容易可以看出,这个程序的作用是利用异或运算来交换x和y的值,但如果你运行后,就会发现,打印的结果是x=0;y=1984,交换失败了。平时我们交换内容采用的最常用的方法是利用中间变量来进行:
temp = x;
x = y;
y = temp;
而这个程序采用方法实质上是省去了中间变量,我们可以把它拆分成:
x = x ^ y;
y = y ^ x;
x = y ^ x;
乍一看,似乎利用异或运算省去了中间变量,是一种聪明的方法,然而,这种做法并不能保证是绝对正确运行的,而且也不利于程序的阅读。C语言和C++中都会使用这种方法,但也不能确定在这两者中都可以正确运行,而且在java中是不能正确运行的。java语言规范描述了:操作符的操作数是从左向右求值的。为了求表达式x^=y的值,在计算y之前提取x的值,并且将这两个值的异或结果赋给变量x。在程序中,变量x的值被提取了两次,每次在表达式中出现时都提取一次,但是两次提取都发生在所有的赋值操作之前。下面的代码就详细的描述了将互换惯用法(即使用异或运算)分解之后的行为,并且解释了为什么会打印出上面的结果:
int temp1 = x; //第一次提取x的值
int temp2 = y; //第一次提取y的值
int temp3 = x ^ y; //计算 x ^ y
x = temp3; //进行赋值,此时将x^y的值赋给x
y = temp2 ^ temp3; //将x的原始值赋给y
x = temp1 ^ y; //temp1还是x的原始值,temp1^y的值为0,然后再赋给x
在C和C++中,并没有指定表达式的计算顺序。当编译表达式x^=y时,许多C和C++的编译器都是在计算等号右边的值后才提取X的值,这就使得上述的惯用法(异或运算)可以正常运转,尽管可以正常运转,它仍然违背了C/C++有关不能在两个连续的序列点之间重复修改变量的规则,因此,在C和C++中也没有明确定义这个方法的行为。为了突出其价值,还是可以写出不用临时变量就可以互换两个变量内容的java表达式,但这并不是“聪明的做法”。
所以说在单个表达式中不要对相同的变量赋值两次。表达式如果包含对相同的变量进行多次赋值,就会引起混,乱,并且很少能够执行所希望的操作。所以有时宁愿选择“笨”一些的方法也不要去使用这些“聪明”的方法。它们都容易产生bug,难以维护,并且运行速度经常比它们所替代的简单直观的代码慢。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: