在Java中,对 byte 和 short 类型 进行位操作的时候,严重留意事项


参考:

============================================================

总结:在java中,对byte和short类型的 右移操作 必须先进行 & 0xff 后再右移,避免byte或short是负数的情况下,导致 右移操作前 自动升为int,前面补了很多1,此时右移会把1冲到高位上,从而错误;

int 和  long没有任何问题;

左移没有这个问题,因为左移及时自动转换成int 在前面补了很多1后,后面的截断 还是会把左边的都截掉,就是说 左移 永远是从右边补0,而右移由于自动转换成int的存在,会导致即使使用了>>>的情况下

左边还是会补1,因为负数转换成int的时候,前面的每一位都是1了。留意。

((bytes[0] & 0xff) >>> 3);

1.举例:

    public static void main(String[] args) {
        byte[] bytes = new byte[1];
        bytes[0] = 31;//00011111
        bytes[0] <<= 3;//11111000
        bytes[0] >>>= 3;// 这步很诡异的变成了 11111111 ????
        System.out.println(bytes[0]);// -1;最终的结果为-1???
    }

接下来调试看下:

导致输出的结果为-1,而不是31的原因是,在java中 对byte和 short进行位操作的话,会先默认自动转换为int 再进行位操作;

    public static void main(String[] args) {
        byte[] bytes = new byte[1];
        bytes[0] = 31;//00011111
        /*
         bytes[0] <<= 3;这步发生的情况如下:
         0000 0000 0000 0000 0000 0000 0001 1111(先把byte[0]转换成int)
         0000 0000 0000 0000 0000 0000 1111 1000(再左移3位)
         1111 1000(再赋值给byte[0],截断)
         */
        bytes[0] <<= 3;

        /*
         bytes[0] >>>= 3; 又发生了什么:
         1111 1111 1111 1111 1111 1111 1111 1000(把当前的byte[0]转换成int,由于是负数,所以转换成了这样,左边按符号位全部补1,就是由这步自动转换导致了问题,解决方法就是把这步自动转换前面的1去除,用 & 0xff)
         0001 1111 1111 1111 1111 1111 1111 1111(右移3位)
         1111 1111(赋值截断,最终 byte[0]的值,可见变成全是1了)
         */
        bytes[0] >>>= 3;


        /*
         输出byte[0]发生了什么,输出byte[0]就是把byte[0]的值转换成10进制,计算机发现byte[0]的最高位是1,说明是负数,
         计算机认为它是负数后,负数在计算机中是以补码的方式来存储的,所以具体的10进制的值是它的原码,需要把补码转换成原码
         规则:1.补码符号位不变,其余位取反;
              2.取反后加1,就是原码
              1000 0000(符号位不变,其余位取反)   
              1000 0001(取反后加1,就是原码) 
              原码就是具体的值,可见是-1
         */
        System.out.println(bytes[0]);
    }

解决方法,系统自动把byte[0]由byte自动向int 转换后的值再与0xff取与运算,使其一个字节的前面的位全部为0:

1111 1000 --> 1111 1111 1111 1111 1111 1111 1111 1000(自动向int转换)

然后我们再通过& 0xff 让它们取与运算:

1111 1111 1111 1111 1111 1111 1111 1000

0000 0000 0000 0000 0000 0000 1111 1111

=

0000 0000 0000 0000 0000 0000 1111 1000(这个才是我们想要的)

与&0xff 运算后,再说右移的事,就解决了这个问题;

总结:在java中,操作byte右移前一定要先 &0xff 做与运算,才能右移;

    public static void main(String[] args) {
        byte[] bytes = new byte[1];
        bytes[0] = 31;//00011111
        bytes[0] <<= 3;
        bytes[0] = (byte) ((bytes[0] & 0xff) >>> 3);
        System.out.println(bytes[0]);
    }

==================================================================================================================

接下来看下short:

看下 int :

看下long:

相关