zoukankan      html  css  js  c++  java
  • Java> 有趣的byte及位运算

    byte存储范围,表示范围

    我们知道byte代表1个字节,数据存储的范围:[0x00, 0xFF]。byte变量表示值的范围:[-128, 127]。

    下面这段代码并不是输出128,而是输出-128,因为byte变量表示值的范围为[-128, 127]。128刚刚好超出上界127有1单位,溢出为-128。
    300对应byte值也不是300,而是按byte长度(1字节)截取存储内容后的值。
    可以看到,300 = 0b100101100,截取1byte长度后,值为0b00101100,也就有 b = 0b00101100 => b = 44

    byte b = (byte) 128;
    System.out.println(b); // 输出-128
    
    byte b = (byte) 300; // 300 = 0b100101100, b = 0b101100
    System.out.println(b); // 输出44
    

    byte位运算

    还有一种比较有意思的现象,就是byte位运算,中间过程是否进行类型转换,也会影响结果。
    请看下面的代码,分别打印出什么?(i1, i2):

    byte a = (byte)0xFF;
    int i1 = 0xFF & a;
    int i2 = a;
    
    System.out.println(i1); // 打印255
    System.out.println(i2); // 打印-1
    

    运行程序,发现打印i1 为255,打印i2为-1,同样的byte类型变量a = 0xFF,如果直接转换为int类型,值为-1;如果与0xFF先进行按位与运算,值为255。
    中间只是对a和0xFF进行了与运算,而a本身宽1字节,但打印结果却不同,这是为什么呢?
     
    猜测是不是跟运算过程中的类型转换有关。下面先做验证:

    1. 全部显式转换为byte类型,再 &;
    2. 全部显式转换为int类型,再&;
    byte a = (byte)0xFF;
    int i1 = 0xFF & a;
    int i2 = a;
    int i3 = (byte)0xFF & (byte)a;
    int i4 = (int)0xFF & (int)a;
    
    System.out.println(i1); // 打印255
    System.out.println(i2); // 打印-1
    System.out.println(i3); // 打印-1
    System.out.println(i4); // 打印255
    

    根据打印结果,可以得出结论:

    1. byte型数据跟int型数据进行运算时,会先默认转换为int类型。(类型提升)
    2. byte -> int直接类型转换,并不能改变数的符号。

     
    byte型位运算为何结果不同于int型位运算?
    int和byte都可以表示负数,为什么转换为int进行 & ,与转换为byte进行&,为何结果不一样?
    由结论2,知因为int i4 = (int)0xFF & (int)a;中的类型转换(int)并不会改变符号,那么是什么时候改变的呢? 只可能是与0xFF进行&时,改变了a的符号。因为结果是255,但byte a = -1,而i2 = a值也是-1。
    详细分析知,0xFF是1byte,而int是2byte。
    由于a是int类型,4byte存储,实际a存储值 = 补码(a) = 反码(-a) + 1 = 反码(1) + 1 = ~0b0000 0000 0000 0000 0000 0000 0000 0001 + 1 = 0b1111 1111 1111 1111 1111 1111 1111 1111 = 0xFFFF FFFF
    可知,

    int i4 = 0xFF & (int)a 
       = 0xFF & -1
       = 0xFF & 0xFFFF FFFF 
       = 0xFF,符号位为0,是正数 
    => i4 = 255
    

    不妨将0xFF改成成0xFFFFFFFF,来验证上面的猜测:

    byte a = (byte)0xFF;
    ...
    int i4 = (int)0xFF & (int)a;
    int i5 = 0xFFFFFFFF & a;
    
    ...
    System.out.println(i4); // 打印255
    System.out.println(i5); // 输出-1
    

    可以得到i5 = -1,符合猜测预期。 因此,需要十分注意类型转换过程中值的变化,还有位宽的变化,特别是涉及到负数,因为计算机中存储的是补码,就会涉及到符号位。

  • 相关阅读:
    easyui 如何为datagrid添加自定义列属性(如:width,align,editor)
    Oracle中如何修改已存在数据的列名的数据类型
    web 表单方式上传文件方法(不用flash插件)
    easyui datagrid怎么动态获取表头的列名及显示名称
    如何解决“HttpException (0x80004005): 超过了最大请求长度”问题
    oracle中“ORA-00060: 等待资源时检测到死锁” 或存储过程编译卡死 解决方法
    Chosen v1.8.7 动态添加下拉选项
    【转发】vue v-for循环的用法(索引,键值)
    Vue Select默认选择项设置方法
    Vue内部使用setInterval轮询数据,对象数据重新赋值后再次渲染数据
  • 原文地址:https://www.cnblogs.com/fortunely/p/14277050.html
Copyright © 2011-2022 走看看