Java byte转int时为什么要与0xff进行与运算?

先来看个栗子:

 byte[] bs = digest.digest(origin.getBytes(Charset.forName(charsetName))) ;  
          
 for (int i = 0; i < bs.length; i++) {  
     int c = bs[i] & 0xFF ;
     if(c < 16){ 
          sb.append("0");  
     }  
     sb.append(Integer.toHexString(c)) ;  
 }  
 return sb.toString() ;

bs是由一段字符串经过MD5加密后输出的byte数组。在for循环里,bs[i]是一个8位二进制,而0xFF的二进制为11111111,那么bs[i]与0xFF进行与运算,得到仍为bs[i],不是多此一举吗,为什么要这样做呢?

在搞清楚之前,需要理解计算机存储机制以及原码、反码、补码的概念:

在学计算机原理时,知道计算机内部的存储都是利用二进制的补码进行存储的,如果用1个字节表示一个数字,一个字节有8位,超过8位就进1,在内存中的情况为:100000000,进位1被丢掉。

来回顾下反码、补码的概念:

反码

对于正数,反码和原码相同;

对于负数:反码是除符号位1之外的都取反。

补码:就是对反码加1

比如:

-1 的原码:10000001

-1 的反码:11111110

                               +1

-1 的补码:11111111

 

0 的原码:00000000

0 的反码:11111111(正零和负零的反码相同)

                             +1

0 的补码:100000000 (1丢掉,正零和负零的补码相同)

-----------------------------------------------------------------------------------

由上述可知,byte a = -127(原码:11111111)在内存中会以其补码(10000001)的形式存储,在做byte -> int类型转换时,JVM会做一个补位处理,由于int类型为32位,所以补位后的补码为:11111111 11111111 11111111 10000001(32位),这个32位二进制补码也是-127。(注:补位是补1还是补0,取决于byte的最高位是1还是0)

我们发现,在byte -> int转换时,计算机存储的补码和JVM补位后的补码表示的十进制数字仍然是相同的。

所以,在byte类型转为int类型时,为什么要和0xFF(原码:11111111)做与运算?其本质原因是要和二进制补码保持一致。当byte转int时,高24位必然会补1,这时与其二进制补码已经不一样了,补位后的补码与0xFF 做与运算,可以将高24位置为0,低8位保持不变,这样做就可以保证和二进制补码的一致了。

 

你可能感兴趣的:(java)