java移位运算、逻辑运算、异或及取反运算

最近看源码,复习了下基础运算知识,做下记录,一些表述与其他或者官方有些诧异,纯属个人心得,欢迎参考借鉴,指出错误,共勉。

    public static void main(String[] args) {

        //正数左移: 简单的理解为 移几位就在右边加几个0依次计算
        System.out.println(3 << 1);//6 3乘以2的1次方 11 ==> 110 [4+2+0]
        System.out.println(3 << 2);//12 3乘以2的2次方 11 ==> 1100 [8+4+0+0]
        System.out.println(3 << 3);//24 3乘以2的3次方 11 ==> 11000 [16+8+0+0+0]
        System.out.println(3 << 4);//48 3乘以2的4次方 11 ==> 110000 [32+16+0+0+0+0]
        System.out.println(3 << 5);//96 3乘以2的5次方 11 ==> 1100000 [64+32+0+0+0+0+0]

        //负数左移: 先获取补码,低位补0,高位超出舍弃,再取移位后的反码,再取补码[最终结果],以上操作符号位都不变
        //原码 ==> 反码 ==> 补码 ==> 移位 ==> 再取反码 ==> 再取补码(最终结果)
        System.out.println(-7 << 3);  //-56
        /*
        原码 1000 0000 0000 0000 0000 0000 0000 0111
        反码 1111 1111 1111 1111 1111 1111 1111 1000 [符号位不变,按位取反]
        补码 1111 1111 1111 1111 1111 1111 1111 1001 [符号位不变,反码+1]
        移位 1111 1111 1111 1111 1111 1111 1100 1000 [*符号位不变,高位超出位舍弃,低位补0]
   再取反码  1000 0000 0000 0000 0000 0000 0011 0111 [符号位不变,按位取反]
   再取补码  1000 0000 0000 0000 0000 0000 0011 1000 [符号位不变,反码+1]
         */

        System.out.println(-297 << 5); //-9504
        /*
        原码 1000 0000 0000 0000 0000 0001 0010 1001
        反码 1111 1111 1111 1111 1111 1110 1101 0110 [符号位不变,按位取反]
        补码 1111 1111 1111 1111 1111 1110 1101 0111 [符号位不变,反码+1]
        移位 1111 1111 1111 1111 1101 1010 1110 0000 [*符号位不变,高位超出位舍弃,低位补0]
   再取反码  1000 0000 0000 0000 0010 0101 0001 1111 [符号位不变,按位取反]
   再取补码  1000 0000 0000 0000 0010 0101 0010 0000 [符号位不变,反码+1]
         */

        //正数右移(有符号右移): 简单的理解为 移几位 左边就删几位0依次计算
        System.out.println(96 >> 1);//48 96除以2的1次方 1100000 ==> 0110000 [0+32+16+0+0+0+0]
        System.out.println(96 >> 2);//24 96除以2的2次方 1100000 ==> 0011000 [0+0+16+8+0+0+0]
        System.out.println(96 >> 3);//12 96除以2的3次方 1100000 ==> 0001100 [0+0+0+8+4+0+0]
        System.out.println(96 >> 4);//6 96除以2的4次方 1100000 ==> 0000110 [0+0+0+0+4+2+0]
        System.out.println(96 >> 5);//3 96除以2的5次方 1100000 ==> 0000011 [0+0+0+0+0+2+1]


        //负数右移 : 获取反码 => 补码 => 移位[符号位不变,高位补1,低位超出位舍弃] => 再取移位后的反码 =>取移位后的补码
        System.out.println(-56 >> 3); //-7
        /*
          原码 1000 0000 0000 0000 0000 0000 0011 1000
          反码 1111 1111 1111 1111 1111 1111 1100 0111 [符号位不变,按位取反]
          补码 1111 1111 1111 1111 1111 1111 1100 1000 [符号位不变,反码+1]
          移位 1111 1111 1111 1111 1111 1111 1111 1001 [*符号位不变,高位补1,低位超出位舍弃]
     再取反码  1000 0000 0000 0000 0000 0000 0000 0110 [符号位不变,按位取反]
     再取补码  1000 0000 0000 0000 0000 0000 0000 0111 [符号位不变,反码+1](最终结果)
         */

        System.out.println(-139 >> 5); //-5
        /*
          原码 1000 0000 0000 0000 0000 0000 1000 1011
          反码 1111 1111 1111 1111 1111 1111 0111 0100 [符号位不变,按位取反]
          补码 1111 1111 1111 1111 1111 1111 0111 0101 [符号位不变,反码+1]
          移位 1111 1111 1111 1111 1111 1111 1111 1011 [*符号位不变,高位补1,低位超出位舍弃]
     再取反码  1000 0000 0000 0000 0000 0000 0000 0100 [符号位不变,按位取反]
     再取补码  1000 0000 0000 0000 0000 0000 0000 0101 [符号位不变,反码+1](最终结果)
         */

        //正数无符号右移
        //有符号右移:正数的符号位为0,移动时,符号位不动,高位补0
        //无符号右移:高位补0,符号位跟随移动,符号位移动后也未0,
        //其实和有符号位移所得结果是一样的,所以宏观上将,正数的有符号位移和无符号位移是没啥区别的
        System.out.println(200 >> 5); //6
        /*
          原码 [0]000 0000 0000 0000 0000 0000 1100 1000
          移位 [0]000 0000 0000 0000 0000 0000 0000 0110
         */
        System.out.println(200 >>> 5); //6
        /*
          原码 [0]000 0000 0000 0000 0000 0000 1100 1000
          移位 0000 0[0]00 0000 0000 0000 0000 0000 0110
         */

        //负数无符号右移
        System.out.println(-200 >>> 5); //134217721
        /*
        原码 1000 0000 0000 0000 0000 0000 1100 1000
        反码 1111 1111 1111 1111 1111 1111 0011 0111 [符号位不变,按位取反]
        补码 1111 1111 1111 1111 1111 1111 0011 1000 [符号位不变,反码+1]
        移位 0000 0111 1111 1111 1111 1111 1111 1001 [*符号位也要偏移, 高位补符号位0, 低位超出位数舍弃](符号位变为0,为正数,三码合一,不用继续转换)(最终结果)
         */

        System.out.println(-9 >>> 4); //268435455
        /*
        原码 1000 0000 0000 0000 0000 0000 0000 1001
        反码 1111 1111 1111 1111 1111 1111 1111 0110 [符号位不变,按位取反]
        补码 1111 1111 1111 1111 1111 1111 1111 0111 [符号位不变,反码+1]
        移位 0000 1111 1111 1111 1111 1111 1111 1111 [*符号位也要偏移, 高位补符号位0, 低位超出位数舍弃](符号位变为0,为正数,三码合一,不用继续转换)(最终结果)
         */

        //或运算 & 规则 :都为1时才为1
        System.out.println(5 | 6); //值:7
        /* 5: 101
           6: 110
        或值: 111 ==> [4+2+1] ==> 7
         */
        System.out.println(520 | 20); //值:540
        /* 520: 1000001000
            20:   0000010100
        或值:   1000011100 ==> [512+0+0+0+0+16+8+4+0+0] ==>  540
         */

        //与运算 | 规则:有一个为1,则为1
        System.out.println(5 & 6); //值:7
        /* 5: 101
           6: 110
        与值: 100 ==> [4+0+0] ==> 4
         */
        System.out.println(520 & 20); //值:0
        /* 520: 1000001000
            20: 0000010100
        或值:   0000000000 ==> [0+0+0+0+0+0+0+0+0+0] ==>  0
         */

        System.out.println(88 & 66); //值:0
        /* 88: 1011000
           66: 1000010
         或值: 1000000 ==> [64+0+0+0+0+0+0] ==>  64
         */

        //异或运算  ^ 规则:不同为1(左边补0不做计算)
        System.out.println(5 ^ 6); //值:3
        /* 5: 101
           6: 110
       异或值: 011 ==> [0+2+1] ==> 3
         */
         System.out.println(520 ^ 20); //值:540
        /* 520: 1000001000  => 0111110111
            20: 0000010100  =>      01011
         异或值: 1000011100 ==> [512+0+0+0+0+16+8+4+0+0] ==>  540
         */

         System.out.println(88 ^ 66); //值:0
        /* 88: 1011000
           66: 1000010
        异或值: 0011010 ==> [0+0+16+8+0+2+0] ==>  26
         */

        //取反运算 ~ 规则:按位取反
        // 正数步骤 原码取反(值1) ==> 值1-1[符号位不变](值2) ==> 再取反[符号位不变](值3) ==> 转成10进制[注意符号位:1负数;0正数]
        System.out.println(~7); // -8
        /*
        7: 0000 0000 0000 0000 0000 0000 0000 0111
      取反:1111 1111 1111 1111 1111 1111 1111 1000   负数的补码
    求反码:1111 1111 1111 1111 1111 1111 1111 0111  补码减1 ()
再取反得原码:1000 0000 0000 0000 0000 0000 0000 1000 得原码
符号位为1 确定值为负数;1000 转为10进制为8 ===> -8
         */

        System.out.println(~9); //-10
        /*
原码、反码、补码: 0000 0000 0000 0000 0000 0000 0001 0001
           取反: 1111 1111 1111 1111 1111 1111 1110 1110
    减一获得补码: 1111 1111 1111 1111 1111 1111 1110 1101
      取反得原码: 1000 0000 0000 0000 0000 0000 0001 0010
         */

        System.out.println(~88); //-89
        /*
原码、反码、补码: 0000 0000 0000 0000 0000 0000 0101 1000
           取反: 1111 1111 1111 1111 1111 1111 1010 0111
           减一: 1111 1111 1111 1111 1111 1111 1010 0110
         再取反: 1000 0000 0000 0000 0000 0000 0101 1001
         */
         
        /**
         * 负数二进制的三种表现形式
         * 1.原码: 绝对值的二进制(符号位为1)
         * 2.反码: 原码取反(符号位不参与运算)
         * 3.补码: 取反之后 + 1
         */
// 负数步骤 转成原码(绝对值原码符号位为1) ==> 原码取反(值1) ==> 值1+1[符号位不变](值2) ==> 再取反[符号位不变](值3) ==> 转成10进制[注意符号位:1负数;0正数]
        System.out.println(~-9); //8
        /*
      原码: 1000 0000 0000 0000 0000 0000 0000 1001
      取反: 0111 1111 1111 1111 1111 1111 1111 0110
      加一: 0111 1111 1111 1111 1111 1111 1111 0111
    再取反: 0000 0000 0000 0000 0000 0000 0000 1000
         */

        System.out.println(~-7); //6
        /*
      原码: 1000 0000 0000 0000 0000 0000 0000 0111
      取反: 0111 1111 1111 1111 1111 1111 1111 1000
      加一: 0111 1111 1111 1111 1111 1111 1111 1001
    再取反: 0000 0000 0000 0000 0000 0000 0000 0110
         */

        System.out.println(~-88); //87
        /*
         原码: 1000 0000 0000 0000 0000 0000 0101 1000
         取反: 0111 1111 1111 1111 1111 1111 1010 0111
         加一: 0111 1111 1111 1111 1111 1111 1010 1000
       再取反: 0000 0000 0000 0000 0000 0000 0101 0111
         */

    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章