代码之家  ›  专栏  ›  技术社区  ›  aberrant80

有人能解释一下从字节数组到十六进制字符串的转换吗?

  •  4
  • aberrant80  · 技术社区  · 17 年前

    首先,我从中发现了以下内容 this URL

    private static String convertToHex(byte[] data) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < data.length; i++) {
            int halfbyte = (data[i] >>> 4) & 0x0F;
            int two_halfs = 0;
            do {
                if ((0 <= halfbyte) && (halfbyte <= 9))
                    buf.append((char) ('0' + halfbyte));
                else
                    buf.append((char) ('a' + (halfbyte - 10)));
                    halfbyte = data[i] & 0x0F;
                } while(two_halfs++ < 1);
            }
        return buf.toString();
    }
    

    我还没有发现在Java中需要使用位移位,所以对此我有点生疏了。有人很好地解释了(简单地说)上面的代码是如何进行转换的?“>>”?

    我还发现了其他有关StackOverflow的解决方案,例如 here here ,它改为使用BigInteger:

    try {
       String s = "TEST STRING";
       MessageDigest md5 = MessageDigest.getInstance("MD5");
       md5.update(s.getBytes(),0,s.length());
       String signature = new BigInteger(1,md5.digest()).toString(16);
       System.out.println("Signature: "+signature);
    
    } catch (final NoSuchAlgorithmException e) {
       e.printStackTrace();
    }
    

    为什么这也行得通,哪种方式更有效?

    谢谢你抽出时间。

    4 回复  |  直到 9 年前
        1
  •  10
  •   tschaible    17 年前
    private static String convertToHex(byte[] data) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < data.length; i++) {
    

    到目前为止。。。只需进行基本设置并启动循环,以遍历数组中的所有字节

            int halfbyte = (data[i] >>> 4) & 0x0F;
    

    转换为十六进制时的字节是两个十六进制数字或8个二进制数字,具体取决于您在哪个基中查看它。上述语句将高位4位下移(>>>为无符号右移),并用0000 1111对其进行逻辑和运算,使结果为等于字节高位4位(第一个十六进制数字)的整数。

    假设23是一个输入,这是二进制的0001 0111。移位使和逻辑化,并将其转换为0000 0001。

            int two_halfs = 0;
            do {
    

    这只是将do/while循环设置为运行两次

                if ((0 <= halfbyte) && (halfbyte <= 9))
                    buf.append((char) ('0' + halfbyte));
                else
                    buf.append((char) ('a' + (halfbyte - 10)));
    

    这里我们显示的是实际的十六进制数字,基本上只是使用零或一个字符作为起点,并向上移动到正确的字符。第一个if语句覆盖所有数字0-9,第二个覆盖所有数字10-15(a-f为十六进制)

    同样,使用我们的示例0000 0001,十进制数等于1。我们在上面的if块中被捕获,并将1添加到“0”字符以获得字符“1”,将其附加到字符串并继续。

                    halfbyte = data[i] & 0x0F;
    

    现在我们将整数设置为刚好等于字节的低位,然后重复。

    再说一次,如果我们的输入是23。。。0001 0111在逻辑和之后变为0000 0111,十进制为7。重复上述相同逻辑,显示字符“7”。

                } while(two_halfs++ < 1);
    

    现在我们只需转到数组中的下一个字节并重复。

            }
        return buf.toString();
    }
    

    为了回答您的下一个问题,JavaAPI已经内置了一个到BigInteger的基本转换实用程序。见 toString(int radix) 文档

        2
  •  2
  •   Cowan    17 年前

    要回答这个问题:

    为什么这也行

    没有。至少,与循环版本不同。新的BigInteger(…).toString(16)将不显示前导零,而以前的版本将显示前导零。通常,对于诸如写出字节数组(特别是表示哈希之类的内容)之类的内容,您需要一个固定长度的输出,因此如果您想要使用该版本,则必须适当地填充它。

        3
  •  1
  •   Community Mohan Dere    9 年前

    有关比特移位的详细解释,请查看以下SO问题中的答案 What are bitwise shift (bit-shift) operators and how do they work?

    他似乎试图将一个字节转换成一个小于16的数字,通过这样做,他可以很容易地用代码确定该字节代表哪个字符

      if ((0 <= halfbyte) && (halfbyte <= 9))
                    buf.append((char) ('0' + halfbyte));
                else
                    buf.append((char) ('a' + (halfbyte - 10)));
    

        4
  •  0
  •   kavai77    12 年前

    这些内容您不必自己编写,因为它已经用apache commons编解码器编写:

    import org.apache.commons.codec.binary.Hex;
    ...
    Hex.encodeHexString(byte[] array)
    

    在这方面有很多更有用的方法 Hex