Java中String的hashCode()方法背后的内容是什么?

What's behind the hashCode() method for String in Java?

本问题已经有最佳答案,请猛点这里访问。

我一直在研究爪哇的EDCOX1 0方法,找到了一个字符串类奇怪的。源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

代码本身是非常直接的。但是我想知道用这种方法计算散列码的原因是什么?为什么选择31?为什么从0开始而不是从value.length-1?有没有保证这会减少哈希代码之间的冲突?


是的,哈希代码冲突的概率非常低,例如,对于字符串,它取决于字符串值。如果不使用new运算符创建任何字符串,那么如果新字符串的值与已经存在的值相同,则不会创建新的字符串对象,它引用堆中的旧值,在这种情况下,只有hashcode的值与预期值相同。

hashcode的总合同是:

每当Java应用程序执行过程中在同一对象上多次调用时,HASCODE方法必须始终返回相同的整数,如果没有修改对象中的相等信息。从应用程序的一次执行到同一应用程序的另一次执行,这个整数不需要保持一致。

从Java 1.2,JavaLang.String类使用一个乘积和算法实现整个字符串中的HASCODE()。[2 ]给定一个JavaLang.String类的实例S,将有一个哈希代码H(s)定义。

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

在使用Java32位int加法求和的条件下,s[i]表示字符串的第i个字符,n是s的长度。

对于Apache Harmony中的参考,方法hashcode是:

1
2
3
4
5
6
7
8
9
10
11
12
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;
}