今天看到一位大神的博客,深受感触。决定也发一篇博客,证明一下我还活着。

于是我翻看以前学习时做的一些笔记,整理了一下,得到了一个关于异或运算交换变量变量值的笔记。

首先来看下面三组表达式,看起来他们都能实现交换两个变量的值。

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

a ^= b ^= a ^= b;

可实际的情况是,前面2组表达式,在C、C++、Java中都能顺利完成变量值的交换。而第3组表达式,却只在C、C++中通过了,而在Java中却得到了意料之外的结果。请看下面的截图

在C、C++中得到了想要的结果


而在Java中,却得到了这样的结果

怎么样,是不是很惊讶,在java中,a的值,换给了b,但不管怎么做,a的值都是0,怎么会这样?百思不得其解。这事就此搁了下来。

过了很长时间之后,在意个偶然的机会中,我在一个关于Java谜题的手册中看到了这个问题,原来这还是Java比较经典的谜题之一了。

原来,事情是这样的。

很久以前,当中央处理器只有少数寄存器时,人们发现可以通过利用异或操作符(^)的属性(x ^ y ^ x) == y来避免使用临时变量,这个惯用法曾经在C编程语言中被使用过,并进一步被融入到了C++中,但是它并不保证都可以正确运行。但是有一点可以肯定:它在Java中肯定是不能正确运行的。 

Java语言规范描述到:操作符的操作数是从左向右求值的。为了求表达式 x ^= expr的值,x的值是在计算expr之前被提取的,并且这两个值的异或结果被赋给变量x。在OprDemo程序中,变量x的值被提取了两次——每次在表达式中出现时都提取一次——但是两次提取都发生在所有的赋值操作之前。

下面的代码可以很好的解释其原理,并且解释了为什么会得到这样的结果
// Java中x^= y^= x^= y的实际行为
int tmp1 = x ; // x在表达式中第一次出现
int tmp2 = y ; // y的第一次出现
int tmp3 = x ^ y ; // 计算x ^ y
x = tmp3 ; // 最后一个赋值:存储x ^ y 到 x
y = tmp2 ^ tmp3 ; // 第二个赋值:存储最初的x值到y中
x = tmp1 ^ y ; // 第一个赋值:存储0到x中

从上面的代码可以看出,其实a之所以会为0,是因为a^a造成的,我们知道,两个相同的值异或其值为0.


在C和C++中,并没有指定表达式的计算顺序。当运行表达式x^=expr时,许多C和C++编译器是在计算expr之后才提取x的值的,这使得上述的做法可以得到正确的结果。

那么在Java中,有没有办法使得不使用中间变量的单个表达式来达到这个目的呢?这是可以的,请看下面的代码。
y = (x^= (y^= x))^ y ; 

这句代码就能够做到

写这么多,最后想说的就是在单个的表达式中不要对同一变量赋值两次,赋值次数多了,就会引起混乱。


C、C++、Java异或运算交换变量变量值的区别的更多相关文章

  1. 用异或运算交换两个整数实现swap函数功能

    对于异或运算有这如下说明: 1^1=0 0^0=0 1^0=1 0^1=1 简单理解就是当两个书相同时结果为0,而两个数不同时异或的结果为1 可用于两个整数的交换,而不用去引入一个中间变量 #incl ...

  2. Java的位运算 待整理

    位运算:二进制运算 Java的异或运算^ 真^假=真 假^真=真 假^假=假 真^真= 假,这四个是在网上copy的例子,真是1,假是0 但它却是说明了Java异或运算的基本法则,那就是:只要两个条件 ...

  3. Java中「与运算,或运算,异或运算,取反运算。」

    版权声明一:本文为博主原创文章,转载请附上原文出处链接和本声明.版权声明二:本网站的所有作品会及时更新,欢迎大家阅读后发表评论,以利作品的完善.版权声明三:对不遵守本声明或其他违法.恶意使用本网内容者 ...

  4. 网络误区:不用中间变量交换2个变量的value,最高效的是异或运算.

    本文记录了不使用中间变量交换2个变量的value,很多的网络留言说是直接异或运算就可以了,而且效率很高,是真的吗? 这里简单的说一下我的环境:Win7 32位,Qt creator 5.4.1 编译器 ...

  5. 对java位运算之异或运算的一点记录

    首先,异或运算是,每个位上的数不同为1,相同为0. 其次,对两个数值变量的值进行三次异或运算就等于是交换了两个变量的值. 例如: int a = 4; int b = 10; a = a ^ b; b ...

  6. 【Java数据结构与算法】简单排序、二分查找和异或运算

    简单排序 选择排序 概念 首先,找到数组中最小的那个元素,其次,把它和数组的第一个元素交换位置(如果第一个元素就是最小的元素那么它就和自己交换).再次,在剩下的元素中找到最小的元素,将它与数组的第二个 ...

  7. java中与运算,或运算,异或运算,取反运算

      //与运算 &  规则 :都为1时才为1        System.out.println( 7 & 9);        /*         *  7二进制 0111     ...

  8. 关于java按位操作运算

    <1>.在了解位移之前,先了解一下正数和负数的二进制表示形式以及关系:举例15和-15:15 的原码: 00000000 00000000 00000000 00001111     补码 ...

  9. HDOJ 1287 破译密码(异或运算)

    Problem Description 有个叫"猪头帮"的国家,采用一种简单的文法加密,他们所用的语言里面只有大写字母,没有其他任何字符:现在还知道他们加密的方法是:只用一个大写字 ...

随机推荐

  1. Bzoj 1703: [Usaco2007 Mar]Ranking the Cows 奶牛排名 传递闭包,bitset

    1703: [Usaco2007 Mar]Ranking the Cows 奶牛排名 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 323  Solved ...

  2. God of War - HDU 2809(状态压缩+模拟)

    题目大意:貌似是一个游戏,首先给出卢布的攻击,防御,还有血量,再给出每升一级增加的攻击防御还有血量,然后又N个敌人,杀死每个敌人都会得到一些经验,求杀死完所有敌人时剩余的最大血量. 分析:因为敌人比较 ...

  3. 分布式还是混合式? 谈CDN架构对服务质量的影响

    传统分布式模型 通 常,内容分发网络(CDN)採用分布式模型.在这样的模型里, 用户的文件存放在一个源server上.而且由大量边缘server负责分发这些文件.这些边缘server的磁盘空间比較小. ...

  4. webservice传递特殊字符时的解决的方法

    webservice soap报文是xml格式交互的,当中针对特殊字符传递无法解析,导致数据处理失败. 解决的方法例如以下: 1.在发送报文之前,针对报文进行base64转码,转义后避免报文中含有特殊 ...

  5. mysql函数count(*)和count(column)的区别(转)

    mysql中count(*)和count(column)使用是有区别的: count(*)对行的数目进行计算,包含NULL count(column)对特定的列的值具有的行数进行计算,不包含NULL值 ...

  6. Web classPath

    classpath,看名字,类路径,这样比如,对于java程序,就是告诉java程序哪里去找类.(java虚拟机都是通过类装载器的)想myeclipse中struts,spring,hibernate ...

  7. 基于HTML5的SLG游戏开发(一):搭建开发环境(2)

          游戏开发过程中经常需要处理各种事件,而HTML5游戏开发中,所有的场景和UI面板都是绘制在Canvas上面,假设需要对某一UI面板上的关闭按钮添加事件监听,采取的方法是对关闭按钮图片资源进 ...

  8. [转] 让ctags支持Javascript

    mac下安装exuberant ctags mac 下自带ctags但是功能有限,要使用一些常用的功能需要安装exuberant ctags 下载exuberant ctags 安装exuberant ...

  9. [转] Spring Boot and React hot loader

    When I develop web applications, I love using React. I'm also a Spring and groovy addict. Those two ...

  10. [转] 一个资深iOS开发者对于React Native的看法

    当我第一次尝试ReactNative的时候,我觉得这只是网页开发者涉足原生移动应用领域的歪门邪道. 我认为一个js开发者可以使用javascript来构建iPhone应用确实是一件很酷的事情,但是我很 ...