首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >一个人是如何学习Java的?(将字节数组转换为十六进制字符串)

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

Stack Overflow用户
提问于 2010-07-13 15:09:48
回答 11查看 1.3K关注 0票数 5

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

代码语言:javascript
复制
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方法,确定我需要使用给它一个字符串字节数组的方法,所以我添加了这个部分。Javadoc接着说:“一旦所有要更新的数据都被更新了,就应该调用其中一个摘要方法来完成哈希计算。”我再次查看了这些方法,并看到该摘要返回了一个字节数组,因此我添加了这个部分。然后,我在新字节数组上使用了"toString“方法来获取可以打印的字符串。但是,当我编译和运行代码时,输出的所有内容如下:

答案是:[B@4cb162d5

我在StackOverflow上做了一些调查,并在这里发现了一些信息:

如何生成MD5哈希?

这给出了以下例子:

代码语言:javascript
复制
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;
}

这似乎是我唯一可能错过的部分是"BigInteger“部分,但我不确定。

所以,在这一切之后,我想我要问的是,你怎么知道如何使用"BigInteger“部分?我错误地认为newBA对象上的“newBA”方法会将其转换为可读的输出,但我显然错了。一个人怎么知道用Java走哪条路呢?我有C的背景,所以这个看起来很奇怪。对于如何在谷歌上搜索如何一直做一些事情,我如何才能变得更好而不必“欺骗”,有什么建议吗?

谢谢大家抽出时间阅读。:-)

EN

回答 11

Stack Overflow用户

回答已采纳

发布于 2010-07-13 15:31:41

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

BigInteger将其作为将字节数组格式化为单个数字的工具。

你所做的是:

  • 具有适当值的构造 BigInteger (在本例中,该值恰好是以字节数组的形式编码的-您的摘要)。
  • 指示BigInteger对象返回该数字的字符串表示(例如纯文本、可读文本),基地16 (例如十六进制)。

而while循环将该值前缀为0-字符,以获得32的宽度。我可能会为此使用String.format,但是无论什么东西浮在你的船上:)

票数 2
EN

Stack Overflow用户

发布于 2010-07-13 15:29:17

在这种特殊情况下,关键是您需要认识到,字节不是“人类可读的”,而是字符。因此,您需要以某种格式将字节转换为字符。对于散列之类的任意字节,通常使用十六进制作为“人类可读的”格式。然后将每个字节转换为一个2字符的十六进制字符串,然后将它们连接在一起。

这与你使用的语言无关。你只需要理解/意识到它是如何以一种语言不可知论的方式“在罩下”工作的。您必须了解您拥有什么(字节数组)和需要什么(一个六边形)。编程语言只是实现预期结果的工具。您只需搜索“功能需求”以及您希望使用的编程语言来实现该需求。例如"在java中将字节数组转换为十六进制字符串“。

尽管如此,您发现的代码示例是错误的。实际上,您应该确定循环中的每个字节,并测试它是否小于0x10,然后将其填充为零,而不是仅根据结果字符串的长度填充零(这不一定是由于第一个字节小于0x10!)。

代码语言:javascript
复制
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中的字节(所有原语数字)都是有符号的。他们有一个负值范围。Java中的byte-128127,而您希望有一个从0255的范围,以获得一个正确的十六进制。你只需要移除这个标志就可以让他们不签名了。上面示例中的& 0xff正是这样做的。

new BigInteger(bytes).toString(16)获得的十六进制与生成MD5生成器的所有其他六边形的结果不兼容。每当您在MD5摘要中有一个负字节时,它们就会有所不同。

票数 6
EN

Stack Overflow用户

发布于 2010-07-13 15:17:04

只要你(最终)理解你把什么拷贝粘贴到你的应用程序:-),谷歌的答案就可以了。

总的来说,我建议从一本好的Java入门书或网络教程开始。有关更多提示,请参见这些线程:

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3238548

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档