hashCode()在Javastring上的一致性

Java String的hashCode值计算为( String.hashCode() ):

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 

有什么情况下(如JVM版本,供应商等)下面的expression式将评估为false?

 boolean expression = "This is a Java string".hashCode() == 586653468 

更新#1:如果你声称答案是“是的,有这样的情况” – 那么请给出一个具体的例子,当“这是一个Javastring”.hashCode()!= 586653468.尝试作为具体/具体尽可能。

更新#2:我们都知道依赖于hashCode()的实现细节通常是不好的。 但是,我正在谈论String.hashCode() – 所以请保持答案集中在String.hashCode()。 在这个问题的背景下,Object.hashCode()是完全不相关的。

早在Java 1.2中我就可以看到这个文档。

虽然一般情况下你不应该依赖一个哈希代码实现保持不变,但现在已经有文档logging了java.lang.String行为,所以改变它会被视为破坏现有的合约。

只要有可能,你不应该依赖哈希代码保持相同的版本等 – 但在我看来, java.lang.String是一种特殊情况,因为algorithm已经被指定…只要你愿意放弃当然,在指定algorithm之前与版本兼容。

我发现了一些关于JDK 1.0和1.1和> = 1.2的内容:

在JDK 1.0.x和1.1.x中,长string的hashCode函数通过采样每个第n个字符来工作。 这很好地保证你会有很多的string散列到相同的值,从而减缓散列表查找。 在JDK 1.2中,函数已经被改进,将结果乘以31,然后按顺序添加下一个字符。 这有点慢,但在避免碰撞方面要好得多。 资料来源: http : //mindprod.com/jgloss/hashcode.html

有些不同之处,因为你似乎需要一个数字:如何使用CRC32或MD5而不是哈希码,你很好去 – 没有讨论,也没有担心…

你不应该依赖一个哈希码等于一个特定的值。 只是它会在相同的执行中返回一致的结果。 API文档说明如下:

hashCode的一般合约是:

  • 只要在Java应用程序的执行过程中多次调用同一个对象,hashCode方法必须始终返回相同的整数,前提是在对象的equals比较中没有使用的信息被修改。 从应用程序的一次执行到同一应用程序的另一次执行,此整数不必保持一致。

编辑由于String.hashCode()的javadoc指定如何计算一个string的哈希代码,任何违反这将违反公共API规范。

如上所述,一般来说,不应该依赖一个类的哈希码保持不变。 请注意,即使后续运行 一个VM上的相同 应用程序也可能产生不同的散列值。 AFAIK Sun JVM的散列函数在每次运行时计算相同的散列值,但不能保证。

请注意,这不是理论上的。 java.lang.String的哈希函数在JDK1.2中进行了更改 (旧哈希具有URL或文件名等分层string的问题,因为它倾向于为末尾只有不同的string生成相同的哈希)。

java.lang.String是一个特殊的情况,因为它的hashCode()的algorithm是(现在)logging下来的,所以你可以依靠它。 我仍然认为这是不好的做法。 如果你需要一个特殊的logging属性的哈希algorithm,只需写一个:-)。

另一个需要担心的问题是Java的早期/晚期版本之间的实现可能发生的变化。 我不相信实现细节是成立的,所以升级到未来的 Java版本可能会导致问题。

底线是,我不会依赖hashCode()的实现。

也许你可以使用这个机制来突出你正在试图解决的问题,这将突出一个更合适的方法。

只是为了回答你的问题,而不是继续讨论。 Apache Harmony JDK实现似乎使用了不同的algorithm,至less看起来完全不同:

Sun JDK

 public int hashCode() { int h = hash; if (h == 0) { int off = offset; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31*h + val[off++]; } hash = h; } return h; } 

阿帕奇和谐

 public int hashCode() { if (hashCode == 0) { int hash = 0, multiplier = 1; for (int i = offset + count - 1; i >= offset; i--) { hash += value[i] * multiplier; int shifted = multiplier << 5; multiplier = shifted - multiplier; } hashCode = hash; } return hashCode; } 

随意自己检查一下…

如果您担心更改和可能不兼容的虚拟机,只需将现有的哈希码实现复制到您自己的实用程序类中,然后使用它来生成您的哈希码。