java中字符串的hashcode算法原理和冲突概率?

问题铺垫

hotspot jdk1.8:

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
    /**
     * Returns a hash code for this string. The hash code for a
     * {@code String} object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using {@code int} arithmetic, where {@code s[i]} is the
     * <i>i</i>th character of the string, {@code n} is the length of
     * the string, and {@code ^} indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
    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;
    }

tips:

h = 31 * h + val[i]; 这里的实际上是整形和字符相加,也就是和字符的对应的 unicode 编码码值或者保留值(高代理区和低代理区)相加(范围即 0-65535,这里可能与是否超过 BMP 无关(代理区模式))


hashcode和equals满足如下条件:

1. equals() 相等的两个对象他们的 hashCode() 肯定相等
2. equals() 不相等的两个对象, hashcode() 有可能相等
3. hashCode() 相等的两个对象他们的 equals() 不一定相等
4. hashcode() 不等,一定能推出 equals() 也不等

我们知道,String 类对 hashcode 和 equals 进行了覆写,相同字符串的值的 equals() 才会相等,当然此时 hashcode 也是相等的 (这里满足了1).
不同字符串值的 hashcode 也可能相等 ( hash 冲突)(这里符合2).


问题

我想问的是 (这也许是个数学问题):

  1. 条件3冲突的概率? s[0]31^(n-1) + s[1]31^(n-2) + ... + s[n-1]
  2. 如何证明String类符合4?
阅读 2.7k
1 个回答

1、字符串的长度虽然有理论的最大值,但是在这个问题里可以按无限来算,而且你没给定源字符串的范围,在此基础上,可以认为hashCode为1~Integer.INT_MAX之间任意的值都有可能。相等的概率自然是1/Integer.INT_MAX。考虑到具体情况,如果输入字符串里有大量的短串,比如"abc" "ac" "mmm"之类,哈希码可能会集中在一个范围。
2、把字符串看作数列A,另外定义一个数列B:
规定B(1) = 31 * A(1)
对于任意大于1的正整数n,B(n) = 31 * B(n-1) + A(n)
用数学归纳法就能知道,A只能得到唯一的B(n)。

宣传栏