用
MessageDigest.getInstance("md5")
初始化,用
MessageDigest.digest(byte[] input)
方法执行MD5加密,返回的结果也是个byte数组。
然后把数组中每一个字节转换成两位的十六进制字符串,如果结果只有一位的话在前面添零补位。
结果就是一个30位长度的MD5字符串了。
1 /** 对数据作MD5加密。 */ 2 public static String hashUp(String src) { 3 String hash = null; 4 5 try { 6 byte[] md5 = MessageDigest.getInstance("md5").digest(src.getBytes()); 7 8 StringBuilder builder = new StringBuilder(); 9 for (byte b : md5) { 10 String hex = Integer.toHexString(0xff & b); 11 if (hex.length() == 1) { 12 builder.append('0'); 13 } 14 15 builder.append(hex); 16 } 17 hash = builder.toString(); 18 } catch (NoSuchAlgorithmException e) { 19 e.printStackTrace(); 20 } 21 22 return hash; 23 }
但是!重点是!
为什么要用0xff来与一下b呢?
因为不这样处理的话b是正数还不要紧,是负数的话结果就不对了。
首先假设MD5结果中某一位是26,byte类型长8位,二进制形式是:
0001 1010
因为toHexString方法需要的参数是int类型,所以要把b强转成int,变成了32位,于是前24位填零补位,二进制形式是:
0000 0000 0000 0000 0000 0000 0001 1010
把参数转成十六进制,结果是:
0000001A
前面的0全部省略,结果是1A,没有问题。
但是这某一位变成了-26会怎么样呢?
负数在计算机中用正数的补码形式存储,于是把26的二进制值每一位取反再加一,结果是:
1110 0110
于是再把它强转为32位,也就是26的补码。这一转不要紧,结果成了:
1111 1111 1111 1111 1111 1111 1110 0110
蔚为大观。
这个时候再四位一转,把它转成十六进制,结果就是:
FFFFFFE6
符号变了一下,结果变得妈都不认识了。
虽然结果好像没什么问题,但是前面的一堆F可不打算直接拿来用。
于是干脆一了百了,把int值的前24位都扔了不要,用0xff,也就是:
0000 0000 0000 0000 0000 0000 1111 1111
与上它:
1111 1111 1111 1111 1111 1111 1110 0110
前24位当场就没了,真是太惨了:
0000 0000 0000 0000 0000 0000 1110 0110
这时候再转成十六进制,结果是E6,虽然跟开始的值不一样,
……
…………
但是反正也没人在乎……