在操纵文件/消息流、执行编码/解码任务、处理图像等应用中,将字节转换为十六进制(反之亦然)是一种常见的操作。Java字节是[-128, +127]范围内的数字,并使用1个有符号字节(8位)表示。十六进制(基数为16)是一个基于16个数字(0、1、2、3、4、5、6、7、8、9、A、B、C、D、E和F)的系统。换句话说,一个字节值的这8位正好可以容纳范围在00到FF之间的2个十六进制字符。十进制 <-> 二进制 <-> 十六进制映射关系如图所示:
图 2.27 - 十进制到二进制到十六进制转换
例如,122在二进制中是01111010。因为0111在十六进制中是7,而1010是A,所以结果是122在十六进制中是7A(也写作0x7A)。那么负字节呢?从上一章我们知道,Java使用正数的二进制补码来表示负数。这意味着-122在二进制中是10000110(保留正数122=1111010的前7位,翻转(1111010)=0000101,加1(0000001)=00000110,并附加符号位1,得到10000110),在十六进制中是0x86。将负数转换为十六进制有多种方法,但我们可以轻松地将较低的4位获取为10000110 & 0xF = 0110,较高的四位为(10000110 >> 4) & 0xF = 1000 & 0xF = 1000(这里,0xF(二进制,1111)掩码仅对负数有用)。由于0110=6,1000=8,所以10000110在十六进制中是0x86。
如果你需要深入了解Java中的位操作,或者你在理解当前主题时遇到问题,那么请考虑阅读《Java完整编码面试指南》的第9章。因此,在代码行中,我们可以依赖这个简单算法和`Character.forDigit(int d, int r)`,它返回给定基数(r)下给定数字(d)的字符表示:
public static String byteToHexString(byte v) {
int higher = (v >> 4) & 0xF;
int lower = v & 0xF;
String result = String.valueOf(
new char[]{
Character.forDigit(higher, 16),
Character.forDigit(lower, 16)}
);
return result;
}
解决这个问题的方法有很多(在捆绑的代码中,你可以看到这种解决方案的另一种风格)。例如,我们知道`Integer.toHexString(int n)`方法返回一个字符串,该字符串表示给定参数的无符号整数在基数16下的值,那么我们只需要对负数应用0xFF(二进制,11111111)掩码即可:
public static String byteToHexString(byte v) {
return Integer.toHexString(v & 0xFF);
}
如果有一种方法我们应该避免,那就是基于`String.format()`的方法。`String.format("%02x ", byte_nr)`这种方法简洁但非常慢!那么反向过程呢?将一个给定的十六进制字符串(例如,7d、09等)转换为字节相当简单。只需获取给定字符串的第一个(d1)和第二个(d2)字符,并应用关系`(byte) ((d1 << 4) + d2)`:
public static byte hexToByte(String s) {
int d1 = Character.digit(s.charAt(0), 16);
int d2 = Character.digit(s.charAt(1), 16);
return (byte) ((d1 << 4) + d2);
}
捆绑的代码中提供了更多示例。如果你依赖第三方库,那么请查看Apache Commons Codec(Hex.encodeHexString())、Guava(BaseEncoding)、Spring Security(Hex.encode())、Bouncy Castle(Hex.toHexString())等,这个列表是开放的。
JDK 17+
从JDK 17开始,我们可以使用`java.util.HexFormat`类。这个类提供了许多静态方法来处理十六进制数,包括`String toHexDigits(byte value)`和`byte[] parseHex(CharSequence string)`。因此,我们可以将字节转换为十六进制字符串,如下所示:
public static String byteToHexString(byte v) {
HexFormat hex = HexFormat.of();
return hex.toHexDigits(v);
}
反之亦然,如下所示:
public static byte hexToByte(String s) {
HexFormat hex = HexFormat.of();
return hex.parseHex(s)[0];
}
在捆绑的代码中,你还可以看到这些解决方案的扩展,用于将字节数组(byte[])转换为字符串,反之亦然。
本文暂时没有评论,来添加一个吧(●'◡'●)