我有一个字节数组。 我希望将该数组的每个字节String转换为相应的十六进制值。

Java中是否有将字节数组转换为十六进制的函数?


当前回答

其他人已经报道了一般情况。但是如果你有一个已知形式的字节数组,例如MAC地址,那么你可以:

byte[] mac = { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };

String str = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
                           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 

其他回答

Use

Integer.toHexString((int)b);

我在这里发帖是因为现有的答案都没有解释为什么他们的方法有效,我认为这对这个问题真的很重要。在某些情况下,这会导致所提出的解决方案显得不必要的复杂和微妙。为了说明这一点,我将提供一个相当简单的方法,但我将提供更多细节来帮助说明为什么它是有效的。

首先,我们要做什么?我们希望将字节值(或字节数组)转换为ASCII中表示十六进制值的字符串。所以第一步是找出Java中的字节是什么:

字节数据类型是一个8位有符号二补整数。最小值为-128,最大值为127(包括)。在大型数组中,字节数据类型对于节省内存非常有用,因为节省内存实际上很重要。它们也可以用来代替int,它们的限制有助于澄清你的代码;变量的范围是有限的这一事实可以作为一种文档形式。

What does this mean? A few things: First and most importantly, it means we are working with 8-bits. So for example we can write the number 2 as 0000 0010. However, since it is two's complement, we write a negative 2 like this: 1111 1110. What is also means is that converting to hex is very straightforward. That is, you simply convert each 4 bit segment directly to hex. Note that to make sense of negative numbers in this scheme you will first need to understand two's complement. If you don't already understand two's complement, you can read an excellent explanation, here: http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html


将二的补数转换为十六进制

一旦一个数是二的补数,那么把它转换成十六进制就非常简单了。一般来说,从二进制转换为十六进制是非常简单的,正如您将在接下来的两个示例中看到的,您可以直接从2的补码转换为十六进制。

例子

例1:将2转换为十六进制。

1)首先将2转换为二进制的2的补码:

2 (base 10) = 0000 0010 (base 2)

2)现在将二进制转换为十六进制:

0000 = 0x0 in hex
0010 = 0x2 in hex

therefore 2 = 0000 0010 = 0x02. 

例2:将-2(2的补数)转换为十六进制。

1)首先将-2转换为二进制的二元补码:

-2 (base 10) = 0000 0010 (direct conversion to binary) 
               1111 1101 (invert bits)
               1111 1110 (add 1)
therefore: -2 = 1111 1110 (in two's complement)

2)现在转换为十六进制:

1111 = 0xF in hex
1110 = 0xE in hex

therefore: -2 = 1111 1110 = 0xFE.

在Java中执行此操作

现在我们已经介绍了这个概念,您将发现我们可以通过一些简单的屏蔽和移动实现我们想要的效果。要理解的关键是,您试图转换的字节已经是2的补码。你不用自己做这个转换。我认为这是这个问题的一个主要混淆点。以下面的字节数组为例:

byte[] bytes = new byte[]{-2,2};

我们只是手动将它们转换为十六进制,但我们如何在Java中做到这一点呢?方法如下:

步骤1:创建一个StringBuffer来保存我们的计算。

StringBuffer buffer = new StringBuffer();

步骤2:隔离高阶位,将它们转换为十六进制,并将它们附加到缓冲区中

Given the binary number 1111 1110, we can isolate the higher order bits by first shifting them over by 4, and then zeroing out the rest of the number. Logically this is simple, however, the implementation details in Java (and many languages) introduce a wrinkle because of sign extension. Essentially, when you shift a byte value, Java first converts your value to an integer, and then performs sign extension. So while you would expect 1111 1110 >> 4 to be 0000 1111, in reality, in Java it is represented as the two's complement 0xFFFFFFFF!

回到我们的例子:

1111 1110 >> 4 (shift right 4) = 1111 1111 1111 1111 1111 1111 1111 1111 (32 bit sign-extended number in two's complement)

然后我们可以用掩码隔离这些位:

1111 1111 1111 1111 1111 1111 1111 1111 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1111
therefore: 1111 = 0xF in hex. 

在Java中,我们可以一次性完成这一切:

Character.forDigit((bytes[0] >> 4) & 0xF, 16);

forDigit函数只是将您传递给它的数字映射到0-F的十六进制数集。

步骤3:接下来我们需要分离低阶位。因为我们想要的比特已经在正确的位置,我们可以把它们屏蔽掉:

1111 1110 & 0xF = 0000 0000 0000 0000 0000 0000 0000 1110 (recall sign extension from before)
therefore: 1110 = 0xE in hex.  

像以前一样,在Java中我们可以一次性完成这些:

Character.forDigit((bytes[0] & 0xF), 16);

把这些放在一起,我们可以把它作为一个for循环,并转换整个数组:

for(int i=0; i < bytes.length; i++){
    buffer.append(Character.forDigit((bytes[i] >> 4) & 0xF, 16));
    buffer.append(Character.forDigit((bytes[i] & 0xF), 16));
}

希望这个解释能让那些想知道在网上找到的许多例子中到底发生了什么的人更清楚。希望我没有犯任何严重的错误,但建议和纠正是非常欢迎的!

最好的解决方案是这样的一句话:

String hex=DatatypeConverter.printHexBinary(byte[] b);

正如这里提到的

试试这个方法:

byte bv = 10;
String hexString = Integer.toHexString(bv);

处理数组(如果我没理解错的话):

byte[] bytes = {9, 10, 11, 15, 16};
StringBuffer result = new StringBuffer();
for (byte b : bytes) {
    result.append(String.format("%02X ", b));
    result.append(" "); // delimiter
}
return result.toString();

正如polygeneluants所提到的,String.format()是与Integer.toHexString()相比的正确答案(因为它以正确的方式处理负数)。

这是我迄今为止发现的运行最快的代码。我在23ms内运行了109015个长度为32的字节数组。我在VM上运行它,所以它在裸机上可能会运行得更快。

public static final char[] HEX_DIGITS =         {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

public static char[] encodeHex( final byte[] data ){
    final int l = data.length;
    final char[] out = new char[l<<1];
    for( int i=0,j=0; i<l; i++ ){
        out[j++] = HEX_DIGITS[(0xF0 & data[i]) >>> 4];
        out[j++] = HEX_DIGITS[0x0F & data[i]];
    }
    return out;
}

然后你就可以做了

String s = new String( encodeHex(myByteArray) );