<p>Java密码体系结构——表示算法类型的对象,如<code>MessageDigest</code>,以及<code>Cipher</code>和{<cd3>}的对象都实现了一个方案,使得对大量数据执行逐段操作成为可能。它们通过使用方法来更新内部状态和最终操作,例如sign/verify或-for <code>MessageDigest</code>-一个名为<code>digest</code>的单个操作,这些操作具有各种重载。在</p>
<p>这些算法的共同点是,当调用“final”操作时,对象的状态是<em>在初始化后直接重置为状态。此状态通常在调用<code>init</code>方法后达到。在</p>
<p>不过,像SHA-1这样的散列算法不需要显式初始化,所以它们在实例化之后直接返回到状态:它们还没有处理任何数据的状态。这样就可以重用哈希算法来散列另一个值。这比实例化一个新对象要稍微有效一些。在</p>
<p>从<a href="https://docs.oracle.com/javase/9/security/java-cryptography-architecture-jca-reference-guide.htm#JSSEC-GUID-6E9FB890-F011-450E-9EC5-EBB358E1D8A1" rel="nofollow noreferrer">JCA developers guide</a>:</p>
<blockquote>
<p>After the message digest has been calculated, the message digest object is automatically reset and ready to receive new data and calculate its digest. All former state (i.e., the data supplied to update calls) is lost.</p>
</blockquote>
<p>因此,在调用<code>digest()</code>之后,对象将重置为尚未接收到任何数据的状态。因此,第二个调用返回空八位字节字符串/字节数组的哈希值。在</p>
<hr/>
<p>引用<a href="https://en.wikipedia.org/wiki/SHA-1#Example_hashes" rel="nofollow noreferrer">from Wikipedia</a>:</p>
<pre><code>SHA1("")
gives hexadecimal: da39a3ee5e6b4b0d3255bfef95601890afd80709
</code></pre>
<p>它与有符号字节<code>[-38, 57, -93, -18, 94, 107, 75, 13, 50, 85, -65, -17, -107, 96, 24, -112, -81, -40, 7, 9]</code>:在注释中输入的值。在</p>
<hr/>
<p>打印的正确哈希确实是</p>
^{pr2}$
<p>大写的十六进制或</p>
<pre><code>[160, 255, 78, 94, 189, 160, 143, 12, 225, 93, 246, 201, 251, 72, 254, 199, 52, 172, 139, 40]
</code></pre>
<p>在Python中是一个无符号字节数组。注意,Java使用的是有符号字节,而不是有符号字节,因此这等于</p>
<pre><code>[-96, -1, 78, 94, -67, -96, -113, 12, -31, 93, -10, -55, -5, 72, -2, -57, 52, -84, -117, 40]
</code></pre>
<hr/>
<p>要计算这个值,只需调用<code>MessageDigest#digest(byte[] input): byte[]</code>就足够了,在您的例子中是<code>byte[] digest = msdDigest.digest(input)</code>,之后您可以先打印出<code>digest</code><em>,然后返回保存字节数组的变量。在</p>
<hr/>
<p>注意,哈希仍然不应该在多个线程上并发使用;一次只能计算一个哈希;这些类不是线程安全的。在</p>