美文网首页
Java 运算符(位运算符)

Java 运算符(位运算符)

作者: Lstone | 来源:发表于2016-08-05 09:22 被阅读364次

    在我们平常查看的源码中能够经常的看到使用位运算符,这些位运算符一般只用于整数类型和字符类型的运算,Java 提供的常用位运算符有:

    操作符 描述
    & 按位与
    \ 按位或
    ~ 按位非
    ^ 按位异或
    >> 右移运算符
    << 左移运算符
    >>> 无符号右移运算符

    & 按位与

    //&(与)运算符的计算规则是 1&1=1 1&0,0&1,0&0 =0 ,只有两位操作数都为1的时候,这两位操作数&(与)运算的结果才为1,否则为0 
    //(包括符号位)
    int bit1 = 0b011;
    int bit2 = 0b110;
    System.out.println(bit1&bit2); 
    //输出结果为2
      0b010
        &
      0b110
    ------
      0b010 = 2
    

    | 按位或 仍然以 bit1和 bit2两个操作数为例

    //| (或)运算符的计算规则是 1|1, 1|0,0|1 = 1 ,0&0 =0  ,只要有一位操作数是1,那么这两个操作数|(或)运算的结果就为1,否则为0
    //符号位也参与运算
    System.out.println(bit1|bit2);
    //输出结果为6
    0b010
       |
    0b110
    ------
     0b110 
    

    **~ 按位非 **~(非)是一个单目运算符,既是对一个操作数进行运算操作

    // ~(非)运算规则是 将操作数的每一位都取反(包括符号位)
    //(包括符号位)
    int bit3 = 0b101;
    System.out.println(~bit3);//输出结果为-6
    根据~(非)运算规则,非运算是将操作数每一位都取反。
    那么 bit3 = 00000000 00000000 00000000 00000101
    对 bit3进行取反 ~bit3 = 11111111 11111111 11111111 11111010
    很显然根据目前的结果 ~bit3与我们输出的结果-6是不匹配的。
    

    造成上面的结果的原因是:
    在计算机中对数值类型的是以二进制补码的形式进行存储和计算的.
    这样我们就可以理解了,此时的bit3是以补码的形式在计算机中存储的,因此输出结果还需要将bit3转换成原码输出出来。
    正数的原码 = 反码 = 补码
    负数的补码 = 原码取反 + 1
    负数的原码 =(补码-1)取反
    ~bit3的符号位为1,代表是一个负数,我们只需要对 bit3(补码)减1再进行取反(不包括符号位)就能得到bit3的原码,也就是输出结果。

    ~bit3  11111111 11111111 11111111 11111010                                      
                                            -1
    ------------------------------------------- 
     反码 = 11111111 11111111 11111111 11111001  
     原码 = 反码取反 =  10000000 00000000 00000000 00000110 = -6   
    

    **^按位异或 **

    //^(按位异或)相同为0,不同为1 ,包括符号位置
    
    int bit 4 = 5 ;
    int bit5 =  5;
    System.out.println(bit4^bit5); //输出结果为0
    //正如前面计算机内都是以二进制补码存储和计算数值的
    bit4  101
    bit5  101
    ---------
          000 //根据^(异或)相同得0,不同的1,计算结果与输出结果相同
    

    >> (右移运算符)

     //a>>b将操作数a向右移动b位 ,空出来的位置使符号位进行填充,正数使用0补位,负数1补位(在 java 中0b 开头代表二进制数据)
    //(包括符号位)
    我们以 4>>2 ,4>>3,-4>>2 ,-4>>3为例子进行讲解,我们假设操作数类型是 byte 类型,byte 类型默认是8位
    //移位后空位常使用符号位进行填充
    4(原)= 4(补)= 4(反) = 0b00000100(补)
    -4(原)= 0b10000100 -4(反)= 0b11111011 -4(补)=0b11111100
    4 >> 2  0b00000100(4的二进制补码)>> 2 = 0b00000001 = 1
    4 >> 3  0b00000100 >> 3 = 0b00000000 = 0
    -4 >>2  0b11111100(补) >> 2 = 0b11111111 转换成原码等于0b10000001 = -1
    -4 >>3  0b11111100(补) >> 3 = 0b11111111 转换成原码等于0b10000001 = -1
    

    << (左移运算符)

    //a<<b将操作数a向左移动b位 (包括符号位),补位和右移不同,空出位置只使用0进行填充,负数求反码的符号位不参与
    //(包括符号位)
    0b11000000_00000000_00000000_00000000 << 1 向做移动1位结果是0b10000000_00000000_00000000_00000000
    

    >>>(无符号右移)

    >>>右移,移动出来的位置全部以0进行补充(包括符号位)
    4>>>2  -> 00000100(补) >>> 2 右移高位补0 结果为 00000001
    -4 >>> 2 ->0b11111100(补码) >>> 右移高位补0 结果为 00111111
    

    ps:在对操作数进行位移运算时候,系统会对位移大小进行优化。例如:
    对一个32位的 int 类型移动34位,如果位移数大于当前类型表示的最大位数,那么系统会34%32 = 2, 位移数是求余的结果,即 4 >> 2 和4 >> 34结果是一样的

    在上面的例子我们为了简单,使用了 byte 类型作为操作数,实际中二进制运算 byte 或者 short 都是会转换到 int类型或者更高的类型进行运算的,我们只是为了方便表达,将其假设会按照byte 类型进行运算

    例1: byte a = 5; 
    

    5并不是默认就是 byte类型,默认是整形,只是系统会帮我们默认转化为 byte 类型

     例2:byte h = 0b11111111 ; 
    

    如果0b11111111默认是 byte 类型,那么 h = -1,但实际并非如此,0b11111111默认的是 int 类型,它会按照 int 类型进行计算后在赋值给 h 变量,由于0b11111111的范围大于 byte 类型的表示范围,所以编辑器会提示我们进行强制转换,在运行中这回发生位溢出.

    补充:
    符号位是参与数值运算的.

    相关文章

      网友评论

          本文标题:Java 运算符(位运算符)

          本文链接:https://www.haomeiwen.com/subject/pgxhsttx.html