Java String的hashCode值计算为(String.hashCode()):
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
是否存在以下表达式评估为false的任何情况(比如JVM版本,供应商等)?
boolean expression = "This is a Java string".hashCode() == 586653468
更新#1:如果您声称答案是“是,有这种情况” - 那么请举一个具体的例子说明“这是一个Java字符串”.hashCode()! = 586653468。尽可能具体/具体。
更新#2:我们都知道,依赖hashCode()的实现细节通常很糟糕。但是,我正在具体谈论String.hashCode() - 所以请将答案集中在String.hashCode()上。 Object.hashCode()在这个问题的上下文中完全不相关。
答案 0 :(得分:95)
我可以看到文档早在Java 1.2。
虽然一般确实不应该依赖于哈希代码实现保持不变,但它现在已经记录了java.lang.String
的行为,因此更改它会被视为违反现有合同
只要有可能,你就不应该依赖于版本之间保持相同的哈希码 - 但在我看来java.lang.String
是一个特例,因为算法已经指定了。只要你愿意在指定算法之前放弃与版本的兼容性,当然。
答案 1 :(得分:18)
我发现了一些关于JDK 1.0和1.1以及> = 1.2:
的内容在JDK 1.0.x和1.1.x中使用hashCode 功能很长的字符串工作 每第n个字符采样。这个 非常保证你会有 很多字符串都是一样的 值,从而减慢Hashtable 抬头。在JDK 1.2中,该函数具有 经过改进,可以使结果倍增 到目前为止31岁然后添加下一个 字符顺序。这是一个 稍微慢一点,但要好得多 避免碰撞。 资料来源:http://mindprod.com/jgloss/hashcode.html
有些不同,因为你似乎需要一个数字:如何使用CRC32或MD5代替哈希码,你很高兴 - 没有讨论,也没有后顾之忧......
答案 2 :(得分:8)
您不应该依赖哈希码等于特定值。只是它会在同一个执行中返回一致的结果。 API文档说明如下:
hashCode的一般合约是:
- 每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象的equals比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,此整数不需要保持一致。
修改强> 由于String.hashCode()的javadoc指定了如何计算String的哈希码,因此违反此规范将违反公共API规范。
答案 3 :(得分:4)
如上所述,通常你不应该依赖类的哈希码保持不变。请注意,即使在相同VM 上运行相同应用程序,也可能产生不同的哈希值。 AFAIK Sun JVM的哈希函数在每次运行时计算相同的哈希值,但这不能保证。
请注意,这不是理论上的。 JDK1.2中java.lang.String was changed的哈希函数(旧哈希在URL或文件名之类的分层字符串方面存在问题,因为它倾向于为字符串生成相同的哈希值,最后只有不同的字符串)
java.lang.String是一种特殊情况,因为hashCode()的算法已经(现在)记录,所以你可以依赖它。我仍然认为这是不好的做法。如果您需要具有特殊文档属性的哈希算法,只需编写一个: - )。
答案 4 :(得分:3)
担心的另一个(!)问题是Java的早期/晚期版本之间可能的实现更改。我不相信实现细节是一成不变的,因此升级到 future Java版本可能会导致问题。
底线是,我不会依赖hashCode()
的实现。
也许您可以通过使用此机制突出显示您实际尝试解决的问题,这将突出显示更合适的方法。
答案 5 :(得分:2)
回答你的问题而不是继续讨论。 Apache Harmony JDK实现似乎使用了不同的算法,至少它看起来完全不同:
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;
}
Apache Harmony
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;
}
随意自行检查......
答案 6 :(得分:2)
如果您担心更改以及可能不兼容的VM,只需将现有的哈希码实现复制到您自己的实用程序类中,然后使用它来生成哈希码。
答案 7 :(得分:0)
哈希码将根据字符串中字符的ASCII值进行计算。
这是String类中的实现,如下所示
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
hash = h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
}
return h;
}
哈希码中的冲突是不可避免的。例如,字符串“ Ea”和“ FB”的哈希码与2236相同