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

谜题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,难以维护,并且运行速度经常比它们所替代的简单直观的代码慢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值