byte aa=-1; //java 补码后为1111 1111
int bb=aa&0xFF;//保持2进制一致进行位与操作
system.out.printf(bb);
输出:255
提示:要了解这个问题首先要了解原码、反码、补码,这里不介绍了,自己百度吧。
根据我的理解,byte=-1时,-1 & 0xff 是等于255,补码是1111 1111
Java中byte是有符号的,但byte输出到控制台或者检测到byte可能转化为int或者和int相计算时,是当作int类型(32位)输出的,会将byte的高位自动补1,扩充到32位,即1111 1111 1111 1111 1111 1111 1111 1111,此时的补码和byte(8位)的补码1111 1111对应的十进制值是一样的,都是-1。
计算机底层为了为了电路方便(具体为什么去看原码、反码、补码),都是采用补码运算(背书),那么从上面知道:
-1 & 0xff = 1111 1111 1111 1111 1111 1111 1111 1111 & 1111 1111 = 0000 0000 0000 0000 0000 0000 1111 1111 = 255
所以结果转化为十进制就是255。
归根结底的原因就是Java的byte类型范围是-128~127,是有符号的,8位开头第一个数字是代表符号的,最后变成32位就被当作正数了。
在C#中byte就不会有这个问题,因为byte范围是0~255,sbtye才相当于Java的byte,避免了这个问题。所以快去学C#……(#滑稽)
system.out.printf((byte)bb); 这样就会输出-1了
除此之外,为什么外面很多代码中btye[]转int都带上&0xFF呢
因为
第一点:int是4字节,int -1时,补码是1111 1111 1111 1111 1111 1111 1111 1111 。
第二点:btye(8位)如上述所说的Java会自动补位1,变成32位,所以为了不让自动补高位的1影响计算,需要与0xFF(1111 1111)相与运算,变成0000 0000 0000 0000 0000 0000 1111 1111。就跟上面的计算是一个样子的
高位为0了,就不会影响接下来的计算了。(可能没解释清楚,大概就这个意思吧,具体可以看看相与&运算时,各种情况的各种结果)
byte[] aa = new byte[]{ -1,0,0,0};
//a[0] bb 最后的字节 表示1111 1111
//a[1] cc 倒数第二个字节 分别表示 0000 0000 和 1111 1111
//a[2] dd 第二个字节 分别表示 0000 0000 和 1111 1111
//a[3] ee 第一个字节 分别表示 0000 0000 和 1111 1111 (最高位&0xFF可以省略)
int bb= aa[0] & 0xFF;
int cc = 0xFF & 0xFF;
int dd = 0xFF & 0xFF;
int ee = 0xFF & 0xFF;
System.out.println((int)((aa[0] & 0xFF)|(aa[1] & 0xFF)<<8|(aa[2] & 0xFF)<<16|(aa[3] & 0xFF)<<24)); //255
System.out.println((int)((aa[0])|(aa[1])<<8|(aa[2])<<16|(aa[3])<<24)); //-1
System.out.println((int)((bb)|(cc)<<8|(dd)<<16|(ee)<<24)); //-1
System.out.println(bb); //255
System.out.println((byte)bb); //-1
俺也是依葫芦画瓢,有错,欢迎指导
参考byte为什么要与上0xff? - 陈其苗 - 博客园www.cnblogs.com