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

时间:2013-03-20 08:18:27

标签: java hashcode

我一直在调查java中的hashCode()方法,发现String类的方法很奇怪。源代码如下:

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?
任何保证这会使哈希码更不可能相互碰撞?

1 个答案:

答案 0 :(得分:4)

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

hashCode的一般合约是:

每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象的equals比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,此整数不需要保持一致。

从Java 1.2开始,java.lang.String类在字符串的整个文本中使用乘积和算法实现其hashCode()。[2]例如,给定java.lang.String类的实例,将具有由

定义的哈希码h(s)
h(s)=s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

其中术语使用Java 32位int加法求和,s [i]表示字符串的第i个字符,n是s的长度。

您在Apache Harmony中的参考方法hashCode是:

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;
}