MD5算法中 byte转int为什么要&0xff (加256)

  1. 在java的MD5算法中,需要将byte数组转换成16进制的时候,需要先转换为int整型,再转为16进制。因为java
    中对byte的所有运算操作均会是首先将byte转化为int, 再行运算。而转换代码如下:
    //先把 byte转化为int。
    i = b[offset];
    //这种情况是i为负数情况
    if(i < 0) {
     i += 256; //相当于  i = i & 0xff;
    }
在这里为什么要 i = i & 0xff 或者是 i += 256呢?请细读下面内容。
  1. 首先我们知道,计算机内的存储都是利用二进制的补码进行存储的。即正数存储的是二进制原码,负数存储的是二进制的补码。因为正数的原码与补码相同。

  2. 我们这里简单回忆下原码,反码,补码的概念(首位表示符号位)

    1. 对于正数(0000 0010) 原码来说,反码 补码 都是一样的。
    2. 对于负数(1000 0010)原码来说,
       反码则是对原码除了符号位(首位)之外取反运算即(1111 1101),
       补码是对反码作+1运算即(1111 1110)
    
  3. 我们还需要知道类型转化时,怎么进行数据扩展(byte类型的长度是8位,int类型则是32位)

    1. 在将低精度转为高精度数据类型的时候,有两种数据扩展方法。

       (1) 补零扩展(用0来补位),保证二进制存储的一致性,但不能保证十进制值不变。
       (2) 符号位扩展(按符号位值来补位),不能保证二进制存储的一致性,但是能够保证十进制值不变。
       
       具体用例子来说明:设byte b[0] = 127;
       对于正数来说两种方法是一样的,原码为0111 1111,补码为 0111 1111
       1.补零扩展:0000 0000 0000 0000 0000 0000 0111 1111
       2.符号位扩展:0000 0000 0000 0000 0000 0000 0111 1111
       
       设byte b[0] = -127;原码为 1111 1111 补码:1000 0001
       1.补零扩展:0000 0000 0000 0000 0000 0000 1000 0001
       2.符号位扩展:1111 1111 1111 1111 1111 1111 1000 0001
       
       在符号位扩展中,1111 1111 1111 1111 1111 1111 1000 0001,
       原码为:1000 0000 0000 0000 0000 0000 0111 1111 为 -127,说明符号位扩展中的确是保持十进制中值的不变。
       但是补码从1000 0001变成了1111 1111 1111 1111 1111 1111 1000 0001 补码表示不相同了,即二进制的存储不一致了。
      
    2. 如果最初的数值类型是有符号的,那么就执行符号扩展(即如果符号位 为1,则扩展为1,如果为零,则扩展为0);如果它是char(无符号的),那么不管它将要被提升成什么类型,都执行补零扩展。而byte是有符号的,所以进行符号位扩展。

  4. 从上面我们可以知道了,对于byte在转化为int的时候,是进行符号位扩展的,那么就是保证了十进制的数值相同,而二进制的存储方式则不一致了。

  5. 实际上,我们在MD5中这里并不是很关心十进制的数值是否相同,而是关心其背后二进制存储的补码的一致性

  6. byte类型的数字要&0xff再赋值给int类型,其本质原因也就是想保持二进制补码的一致性。

     设b[0] = -127 补码:1000 0001
     因为byte是进行符号位扩展的,在转化为int类型的时候,高24位一定是补1(此时的b[0]为负值), 其补码(二进制存储)会发生改变,因此我们需要使其变为相同的。
     
     0xff:二进制则为 0000 0000 0000 0000 0000 0000 1111 1111
     &运算:同1为1,不同则为0
     int i = b[0] & 0xff = 
     1111 1111 1111 1111 1111 1111 1000 0001
     0000 0000 0000 0000 0000 0000 1111 1111
     等于
     0000 0000 0000 0000 0000 0000 1000 0001
     与之前的补码相同。
     但是数值上发生了改变,此时十进制值为 129.
    
  7. 为什么在代码中 i = i & 0xff; 相当于 i = i + 256 且是当 i 为负数的时候呢

    //先把 byte转化为int。
    i = b[offset];
    //这种情况是i为负数情况
    if(i < 0) {
     i += 256; //相当于  i = i & 0xff;
    }

这是因为,byte转int是 数据扩展必定是 符号位扩展(具体看上面内容),而byte类型长度来说 是8位。

对于byte正数来说,第八位是为 0, 
在&0xff 的时候,仍为正数。最高位还是0。

对于byte负数来说,第八位是为 1, 
在&0xff 的时候,就不是负数了,是正数,
因为最高位(第32位是0),而原本的第八位,则不是符号位,不是用于查看是否为正负数。

注意:这时候就有个神奇的地方了,有点抽象:

在这里插入图片描述

  1. 而本身 原码跟补码之间的关系是,原码 取反 加一 等于 补码,最大之差就是256.

     由上面分析,此时就不需要考虑有符号的问题。
     原码(最小值):  0000 0000 取反
     反码:        1111 1111  加一
     补码(最大值):10000 0000  ----- 256
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值