Java完成的byte数组与16进制字符串转化代码:
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
public static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
这段代码中最值得关注的就是
int v = src[i] & 0xFF;
为什么在从byte转化到int需要运用位操作& 0xFF,需要从计算机的数值存储编码来说。
计算机原码,反码,补码
Java中一个byte是8个位,其中最左边的位为符号位。
原码
数值 1,原码为[0000 0001]
数值 -1,原码为[1000 0001]反码
在原码的基础上,正数不变,负数符号位不变,其余各位取反
数值 1,反码为[0000 0001]
数值 -1,反码为[1111 1110]补码
在反码的基础上,正数不变,负数+1
数值 1,补码为[0000 0001]
数值 -1,补码为[1111 1111]
原码,反码,补码存在的原因,参考链接:https://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html
在计算机中数值是以补码的心事存储的。
byte转化成int
在byte转化成int的过程中,Java会进行补位操作,负数左侧补1。
例如:
-127的byte值为:1000 0001
-127由byte转化为int变为:11111111 11111111 11111111 10000001
这样做可以保证-127的int真是数值任然是正确的,即永远是-127值。但是我们在转化成16进制字符串时会多出 0xFF FF FF 6个字符。
转化的过程中保证了数值正确,却修改了补码,而我们想要得到的16进制字符串真实关心的只是原来的补码。
通过& 0xFF位运算,我们可以消除byte转化int左侧补1的操作:
11111111 11111111 11111111 10000001 & 00000000 00000000 00000000 11111111
最后得到的即使我们想要的最初的byte补码
00000000 00000000 00000000 10000001
这样再调用Integer.toHexString,即可获得正确的16进制字符串。