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

一个人是如何学习Java的(将字节数组转换为十六进制字符串)

  •  5
  • Brian  · 技术社区  · 14 年前

    我知道这听起来像是一个宽泛的问题,但我可以用一个例子来缩小范围。我对爪哇很陌生。对于我的一个“学习”项目,我想创建一个内部MD5文件哈希器供我们使用。我一开始很简单,先尝试散列一个字符串,然后再转到一个文件。我创建了一个名为MD5Hasher.java的文件,并编写了以下内容:

    import java.security.*;
    import java.io.*;
    public class MD5Hasher{
        public static void main(String[] args){
            String myString = "Hello, World!";
            byte[] myBA = myString.getBytes();
            MessageDigest myMD;
            try{
                myMD = MessageDigest.getInstance("MD5");
                myMD.update(myBA);
                byte[] newBA = myMD.digest();
                String output = newBA.toString();
                System.out.println("The Answer Is: " + output);
            } catch(NoSuchAlgorithmException nsae){
                // print error here
            }
        }
    }
    

    我访问了java.sun.com来查看java.security的javadocs,以了解如何使用MessageDigest类。阅读之后,我知道我必须使用“getInstance”方法来获得一个可用的MessageDigest对象。Javadoc接着说“数据是通过update方法处理的”,所以我查看了update方法并确定需要使用一个方法,在这个方法中我将字符串的字节数组提供给它,所以我添加了这一部分。Javadoc接着说“一旦所有要更新的数据都被更新了,就应该调用一个digest方法来完成散列计算。”我再次查看了这些方法,发现digest返回了一个字节数组,所以我添加了这部分。然后我对新的字节数组使用了“toString”方法来获得一个可以打印的字符串。然而,当我编译并运行代码时,打印出来的全部内容是:

    答案是:[B@4cb162d5

    How can I generate an MD5 hash?

    下面是一个例子:

    String plaintext = 'your text here';
    MessageDigest m = MessageDigest.getInstance("MD5");
    m.reset();
    m.update(plaintext.getBytes());
    byte[] digest = m.digest();
    BigInteger bigInt = new BigInteger(1,digest);
    String hashtext = bigInt.toString(16);
    // Now we need to zero pad it if you actually want the full 32 chars.
    while(hashtext.length() < 32 ){
        hashtext = "0"+hashtext;
    }
    

    这似乎是我唯一的部分 缺少的是“大整数”部分,但我不确定。

    C级

    感谢大家抽出时间阅读

    11 回复  |  直到 7 年前
        1
  •  2
  •   extraneon    14 年前

    你实际上已经成功地理解了这个信息。您只是不知道如何正确地表示找到的摘要值。你有一个字节数组。读起来有点困难,一个字节数组的toString会产生 [B@somewhere 一点用都没有。

    你要做的是:

    • construct 一个具有适当值的BigInteger(在本例中,该值恰好以字节数组的形式编码-您的摘要)
    • base 16 (例如十六进制)

    while循环在该值前面加上0个字符,以获得32的宽度。我可能会使用String.format,但不管你的船上漂浮着什么:)

        2
  •  6
  •   Community datashaman    7 年前

    这与你所使用的语言无关。你只需要理解/意识到它是如何以一种语言不可知的方式在“蒙面之下”工作的。你必须明白你所做的 (字节数组)以及 希望 (十六进制字符串)。编程语言只是一种 以达到预期的效果。您只需在google上搜索“功能需求”以及您想要用来实现需求的编程语言。例如 convert byte array to hex string in java ".


    也就是说,您找到的代码示例是错误的。你应该确定 每个 循环中的字节,并测试它是否小于 0x10 0x10 !).

    StringBuilder hex = new StringBuilder(bytes.length * 2);
    for (byte b : bytes) {
        if ((b & 0xff) < 0x10) hex.append("0");
        hex.append(Integer.toHexString(b & 0xff));
    }
    String hexString = hex.toString();
    

    更新 @extraneon ,使用 new BigInteger(byte[]) 也是错误的解决方案。这不会取消对字节的签名。Java中的字节(与所有原语数字一样)是有符号的。它们有一个负范围。这个 byte 在Java中,范围从 -128 127 0 255 得到一个合适的十六进制字符串。基本上,你只需要删除标志,使他们不签字。这个 & 0xff 在上面的例子中就是这样。

    new BigInteger(bytes).toString(16) 与世界上已知的所有其他生成MD5的hexstring生成器的结果都不兼容。每当MD5摘要中有一个负字节时,它们就会不同。

        3
  •  2
  •   HalfBrian    14 年前

    MessageDigests计算某物的字节数组,即通常看到的字符串(例如 1f3870be274f6c49b3e31a0c6728957f )实际上只是字节数组到十六进制字符串的转换。

    MessageDigest.toString() MessageDigest.digest().toString() toString a的方法 byte[] MessageDigest.digest() )返回对字节的某种引用,而不是实际的字节。

    在您发布的代码中,字节数组被更改为整数(在本例中是BigInteger,因为它非常大),然后转换为十六进制以打印为字符串。

    摘要计算的字节数组表示一个数字(根据 http://en.wikipedia.org/wiki/MD5

        5
  •  1
  •   Brian Kintz    14 年前

    虽然我担心我没有使用Java来处理MD5哈希的经验,但我可以推荐 Sun's Java Tutorials 作为学习Java的绝佳资源。他们学习了大部分的语言,在我学习Java的时候帮了我很大的忙。

    另外,你也可以四处看看其他问同样问题的帖子,看看有什么建议出现在那里。

        6
  •  1
  •   Justin Ardini    14 年前

    原因是什么 BigInteger int long . 但是,如果您确实想查看字节数组中的所有内容,有另一种方法。你可以把这条线换掉:

    String output = newBA.toString();
    

    使用:

    String output = Arrays.toString(newBA);
    

    数组,而不是引用地址。

        7
  •  0
  •   xor_eq    14 年前

        8
  •  0
  •   Venkat    14 年前

    我也是一个开发新手。对于当前的问题,我建议 " by David Bishop . 它展示了你需要什么等等。。。

        9
  •  0
  •   Paul Richter    14 年前

    不必通过谷歌“作弊” 如何一直做某事?

    如果您将所有内容都转储到main中,那么您就不是在编写Java。

    在这种规模的程序中,main()应该做一件事:创建一个MD5Hasher对象,然后对其调用一些方法。您应该有一个接受初始字符串的构造函数、一个“完成工作”的方法(update、digest)和一个打印结果的方法。

    那么 你可以开始做一些有用的事情。

        10
  •  0
  •   Community datashaman    4 年前

    你可以在这里替换 Java 用你所选择的你还不知道/还没有掌握的语言。即使你用一种特定的语言工作了10年,你仍然会得到 啊哈!这就是它的工作方式!

    toString() 不是返回您想要/期望的表示,而是实现者选择的任何表示。的默认实现 toString() 是这样的( javadoc ):

    返回对象的字符串表示形式。通常,toString方法返回一个字符串,该字符串“以文本形式表示”这个对象。结果应该是一个简洁,但信息丰富的代表,是一个人容易阅读。建议所有子类重写此方法。

    getClass().getName()+'@'+Integer.toHexString(hashCode())

        11
  •  0
  •   CoolBeans Jake    14 年前

    一个人怎么知道 奇怪的。有什么建议吗 不必“欺骗”就更好了 一直在谷歌上搜索如何做某事

    显而易见的答案是1-当你有问题的时候用谷歌(在我看来这并不算作弊),2-阅读关于这个主题的书籍。

    除此之外,我建议你自己找个导师。如果您在工作中没有经验丰富的Java开发人员,那么请尝试加入本地Java开发人员用户组。你可以在那里找到更有经验的开发人员,也许他们会绞尽脑汁来回答你的问题。