zoukankan      html  css  js  c++  java
  • java基础篇 之 位运算符

    按位操作符

    ​ 按位操作符用来操作基本数据类型中的单个“比特”(bit),即二进制位。按位操作符会对两个参数中对应的位执行布尔代数运算,并最终生成一个结果。

    ​ 我们常用的按位操作符有以下几种:

    • &:与,如果参加运算的两个输入位都是1,则结果为1,否则生成一个输出位0

    • |:或,只要有一个输入位为1,则结果为1。换言之,只有两个输入位为0,结果才为0

    • ~:非,非运算符为一元运算符,只对一个操作符操作,也叫取反运算符

    • ^:异或,只有参加运算的两个输入数相反时,才会输出1

      我们做以下实验:

      public class Main {
          public static void main(String[] args) {
              int a = 16;
              int b = 15;
              String binaryStringA = Integer.toBinaryString(a);
              String binaryStringB = Integer.toBinaryString(b);
              // 填充到32位
              String a32 = StringUtils.leftPad(binaryStringA, 32,"0");
              String b32 = StringUtils.leftPad(binaryStringB, 32,"0");
              System.out.println(a+"的二进制为:"+a32);
              System.out.println(b+"的二进制为:"+b32);
              System.out.println("a&b="+(a&b));
          }
      }
      

      输出如下:

    16的二进制为:00000000000000000000000000010000
    15的二进制为:00000000000000000000000000001111
    a&b=0

    
    **解释**:这里因为操作数都是int,所以我将其都填充到32,这样更直观,我们可以看到,转换成二进制后,16,15每个bit上的值都是不一样的,所以最终的运算结果为0
    
    ​	上面我们测试了两个int类型的与操作,不知道大家有没有疑惑,如果参加运算的两个输入数类型不一致会怎么样呢?比如一个为int,另外一个为long呢?
    
    ​	我们来测试下:
    
    ```java
    
    

    ​ 结果如下:

    
    

    我们可以得出结论:

    当数据类型不一致时,会自动将低级的数据类型往高级转,在我们上面的例子中,很明显,a被转成了long类型。

    我们也可以对编译生成的class文件进行反编译,可以看到如下的代码:

    public class Main {
        public Main() {
        }
    
        public static void main(String[] args) {
            int a = 16;
            long b = 9223372036854775807L;
            String binaryStringA = Integer.toBinaryString(a);
            String binaryStringB = Long.toBinaryString(b);
            String a32 = StringUtils.leftPad(binaryStringA, 32, "0");
            String b32 = StringUtils.leftPad(binaryStringB, 64, "0");
            System.out.println(a + "的二进制为:" + a32);
            System.out.println(b + "的二进制为:" + b32);
            System.out.println("a&b=" + ((long)a & b));
        }
    }
    

    可以看到(long)a & b,在这里编译器自动进行了转换。

    或跟异或在这里就不多赘述了,跟与操作差不多。

    需要注意的是,非运算符,这是一个一元运算符,也就是说参与运算的只能有一个输入数,所以对于与,或,非,我们可以与赋值运算符“=”一起使用,但是非不行。比如我们可以写成a&=b或者a|=b,但是非是不行的另外对于布尔类型,不能执行非操作

    移位操作符

    ​ 移位操作符操作的运算对象也是二进制的bit位。移位运算符只能用来处理整数类型(基本类型的一种)。左移运算符(<<)能按照操作符右侧指定的位数将操作符左边的数字向左移动(低位自动补0),对于右移这一操作,分为无符号右移(>>>)跟有符号右移(>>),所谓有符号右移是指,在进行运算时,如果原操作符的符号为正,则在高位补0,若为负,则在高位补1。而无符号右移,代表了不论正负,都会在高位补0。

    ​ 如果对char,byte,short类型的数值进行移位处理,那么在进行操作之前他们会被转成int类型,并且得到的结果也是一个int类型的值。到这里不知道大家会不会有一个疑惑,如果会被转成int类型的话,我们知道int类型的长度为32位(其中一位为符号位),那么如果移位的位数超过32怎么办呢?我们以a>>>n这个表达式为例,n代表移位的位数,实际上更准确的讲,移位的位数=n%32,即n除以32取余。

    ​ 测试代码如下:

    public class Main {
        public static void main(String[] args) {
            // 32%32=0,所以结果还是8
            System.out.println("8>>32=" + (8 >> 32));
            // 33%32=1,所以相当于右移一位,其实右移一位,就是除以2,左移一位就是乘以2
            // 以此类推,右移n位,相当于除以2的n次方
            // 左移n位,相当于乘以2的n次方(在数字没有溢出的前提下结论才成立)
            // 这个结论大家可以用画图的方式自己推导下
            System.out.println("8>>33=" + (8 >> 33));
        }
    }
    

    移位操作符与“=”赋值运算符配合使用

    在这里我们讨论下<<=,>>=,>>>=这几个运算符。

    ​ 主要讨论下面这种情况:我们知道对char,byte,short类型的数据进行移位运算时,会将其转换为int类型,那么在这种情况下,对一个byte类型的数据使用>>=,或者>>>=,会怎么样呢?主要就是讨论,如果运算后的结果超过了byte类型的上限怎么办呢?(这里只是以byte为例,对于其他两种类型也是一样的)

    ​ 测试代码:

    public class Main {
        public static void main(String[] args) {
            byte b = -1;
            System.out.println(Integer.toBinaryString(b));
            b >>>= 10;
            System.out.println(Integer.toBinaryString(b));
            System.out.println(Integer.toBinaryString(b>>>10));
        }
    }
    

    ​ 结果如下:

    11111111111111111111111111111111
    11111111111111111111111111111111
    (0000000000)1111111111111111111111
    

    ​ 这是因为,在运算过程中,byte类型会先转成int类型,但是当被赋值到一个byte上时,会被截断。在这种情况下就出现了这种诡异的情况(括号中的0是我手动补的)

    ​ 补充知识:

    在计算机中,负数以原码的补码形式表达。 
    什么叫补码呢?这得从原码,反码说起。
    
    原码:一个正数,按照绝对值大小转换成的二进制数;一个负数按照绝对值大小转换成的二进制数,然后最高位补1,称为原码。 
    比如 00000000 00000000 00000000 00000101 是 5的 原码;10000000 00000000 00000000 00000101 是 -5的 原码。  
    
    反码:正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反。 
    取反操作指:原为1,得0;原为0,得1。(1变0; 0变1) 
    比如:正数00000000 00000000 00000000 00000101 的反码还是 00000000 00000000 00000000 00000101 ; 
    负数10000000 00000000 00000000 00000101每一位取反(除符号位),得11111111 11111111 11111111 11111010。 
    称:10000000 00000000 00000000 00000101 和 11111111 11111111 11111111 11111010互为反码。  
    
    补码:正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1. 
    比如:10000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010。 
    那么,补码为: 
    11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011 
    所以,-5 在计算机中表达为:11111111 11111111 11111111 11111011
    
  • 相关阅读:
    UITableView移除某行的分割线和让分割线宽度为cell的宽度
    UIButton防止被重复点击
    给View添加手势,防止点击View上其他视图触发点击效果
    自定义导航栏返回时的滑动手势处理
    一个UITableViewCell的简单动画效果
    二维码扫描
    代理的使用
    常用网站
    IOS 自定义View X系列出现一条线条
    UILabel自适应文本,让文本自适应
  • 原文地址:https://www.cnblogs.com/daimzh/p/12854463.html
Copyright © 2011-2022 走看看