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

【转载】java位操作符查漏补缺

2012-12-21 14:56 197 查看
位操作符有以下6种

    & :按位“与”(AND);

    | :按位“或”(OR);

    ^ :按位“异或”(XOR);

    ~ :“取反” (NOT);

    》 :数据右移;

   《 :数据左移;

1) 按位“与”运算

    按位“与”运算符 & 的作用是对运算符两侧以二进制表达的操作数按位分别进行“与”运算,而这一运算是以数中相同的位(bit)为单位的。操作的规则是:仅当两个操作数都为1时,输出的结果才为1,否则为0。

    例如:

    a = 0x88,b = 0x81,则a & b 的运算结果如下:

          0x88    1000 1000    a数

    &   0x81    1000 0001    b数

    =                1000 0000

   通常我们可把按位“与”操作 & 作为关闭某位(即将该位置0)的手段,例如我们想要关闭a数中的第3位,而又不影响其它位的现状,可以用一个数0xF7,即二进制数1111 0111去与a数作按位“与”运算:

          0x88    1000 1000    a数

    &   0xF7    1111 0111    屏蔽数

    =                1000 0000

    注意,这个数除第3位为0外,其它各位均为1,操作的结果只会将a数中的第3位置0,而a数的其它位不受影响。也就是说,若需要某个数的第n位关闭,只需要将该数与另一个数按位相与,另一个数除了相应的第n位为0外,其它各位都为1,以起到对其它各位的屏蔽作用。

    上面的运算可以用a = a &(0xF7) 来表示,也可以用a & =(0xF7) 来表达。

2) 按位“或”运算

    按位“或” 运算符 | 的作用是对运算符两侧以二进制表达的操作数按位分别进行“或”运算,而这一运算是以数中相同的位(bit)为单位的。操作的规则是:仅当两个操作数都为0时,输出的结果才为0,否则为1。

    例如:

    a = 0x88,b = 0x81,则a | b 的运算结果如下:

        0x88    1000 1000    a数

    |   0x81    1000 0001    b数

    =              1000 1001

    通常我们可把按位“与”操作 & 作为置位(即将该位置1)的手段,例如我们想要将a数中的第0位和1位置1,而又不影响其它位的现状,可以用一个数0x03,即二进制数00000011去与a数作按位“或”运算:

       0x88    1000 1000    a数

    |   0x03    0000 0011    屏蔽数

     =             1000 1011

    注意,这个数除第0、1位为1外,其它各位均为0,操作的结果只会将a数中的第0、1位置0,而a数的其它位不受影响。也就是说,若需要某个数的第n位置1,只需要将该数与另一个数按位相“或”,另一个数除了相应的第n位为1外,其它各位都为0,以起到对其它各位的屏蔽作用。上面的运算可以用a = a | (0x03) 来表示,也可以用a | =(0x03) 来表达。

3) 按位“异或”运算

    按位“异或”运算符 ^ 的作用是对运算符两侧以二进制表达的操作数按位分别进行“异或”运算,而这一运算是以数中相同的位(bit)为单位的。异或运算操作的规则是:仅当两个操作数不同时,相应的输出结果才为1,否则为0。

    例如:

    a = 0x88,b = 0x81,则a ^ b 的运算结果如下:

         0x88    1000 1000    a数

    ^   0x81    1000 0001    屏蔽数

    =          0000 1001

    按位“异或”运算 ^ 具有一些特殊的应用,介绍如下:

    ① 按位“异或”运算可以使特定的位取反

    例如:我们想让a数中的最低位和最高位取反,只要用0x81,即二进制数10000001去与它作按位“异或”运算,其运算结果同上式。经过操作后,最高位的值已经由1变0,而最低位的值也已经由0变1,起到了使这两位翻转的效果。其它位的状态保持不变。

    可以看到,这个数除最低位、最高位为1外,其它各位均为0,操作的结果只会将a数中的第0、7位取反,而a数的其它位不受影响。也就是说,若需要某个数的第n位取反,只需要将该数与另一个数按位相“异或”,另一个数除了相应的第n位为1外,其它各位都为0,以起到对其它各位的屏蔽作用。上面的运算可以用a = a ^ (0x81) 来表示,也可以用a ^ =(0x81) 来表达。

    ② 直接交换两个变量的值

    例如,若有变量a = 3,b = 4,想要交换它们的值,可以做如下一组操作:

    a ^ = b

    b ^ = a

    a ^ = b

    首先,a ^ = b:

    a    0000 0011

    ^ b    0000 0100

    a =    0000 0111

    其次,b ^ = a:

    b    0000 0100

    ^ a   0000 0111

    b =    0000 0011

    最后,a ^ = b:

    a    0000 0111

    ^ b    0000 0011

    a =    0000 0100

    这样,a、b两个变量中的值就进行了对调。

4)“取反”运算

    “取反”运算符 ~ 的作用是将各位数字取反:所有的0置为1,1置为0。例如:

    1001 0110 取反后为0110 1001。

5) 数据左移

    左移就是把一个数的所有位都向左移动若干位,在C中用<<运算符.例如:
    int i = 1;

    i = i << 2;    //把i里的值左移2位
    也就是说,1的2进制是000...0001(这里1前面0的个数和int的位数有关,32位机器,gcc里有31个0),左移2位之后变成000... 0100,也就是10进制的4,所以说左移1位相当于乘以2,那么左移n位就是乘以2的n次方了(有符号数不完全适用,因为左移有可能导致符号变化,下面解释原因)
    需要注意的一个问题是int类型最左端的符号位和移位移出去的情况.我们知道,int是有符号的整形数,最左端的1位是符号位,即0正1负,那么移位的时候就会出现溢出,例如:
int i = 0x40000000; //16进制的40000000,为2进制的01000000...0000

i = i << 1;
     那么,i在左移1位之后就会变成0x80000000,也就是2进制的100000...0000,符号位被置1,其他位全是0,变成了int类型所能表示的最小值,32位的int这个值是-2147483648,溢出.如果再接着把i左移1位会出现什么情况呢?在C语言中采用了丢弃最高位的处理方法,丢弃了1之后,i的值变成了0.
    左移里一个比较特殊的情况是当左移的位数超过该数值类型的最大位数时,编译器会用左移的位数去模类型的最大位数,然后按余数进行移位,如:
    int i = 1, j = 0x80000000; //设int为32位

    i = i << 33;     // 33 % 32 = 1 左移1位,i变成2

    j = j << 33;     // 33 % 32 = 1 左移1位,j变成0,最高位被丢弃
    在用gcc编译这段程序的时候编译器会给出一个warning,说左移位数>=类型长度.那么实际上i,j移动的就是1位,也就是33%32后的余数.在gcc下是这个规则,别的编译器是不是都一样现在还不清楚.
    总之左移就是: 丢弃最高位,0补最低位

6) 数据右移

    右移的概念和左移相反,就是往右边挪动若干位,运算符是>>.
    右移对符号位的处理和左移不同,对于有符号整数来说,比如int类型,右移会保持符号位不变,例如:
    int i = 0x80000000;

    i = i >> 1;    //i的值不会变成0x40000000,而会变成0xc0000000
    就是说,符号位向右移动后,正数的话补0,负数补1,也就是汇编语言中的算术右移.同样当移动的位数超过类型的长度时,会取余数,然后移动余数个位.
    负数10100110 >>5(假设字长为8位),则得到的是    11111101
    总之,在C中,左移是逻辑/算术左移(两者完全相同),右移是算术右移,会保持符号位不变.实际应用中可以根据情况用左/右移做快速的乘/除运算,这样会比循环效率高很多.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JAVA