/**
* 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;
}
上述为Java中String类的hashCode源码,可以看到其中使用了31作为计算hash值的一个固定常量,那么为什么要用31作为常数,而不是其他的值呢?
原因一:发生哈希冲突的可能性更低
31在质子数中“不大不小”,如果使用一个较小的质数如2,那么算出来的哈希值会在一个很小的范围,就会很容易造成哈希值的冲突。而如果选择100以上的质数,算出来的哈希值会超过int的范围(-2147483648 ~ 2147483647),所以这两种都不合适。根据测试,对超过50000个英文单词使用常数 31,33,37,39,41 作为乘子进行哈希值运算,每个常数算出来的哈希值冲突都小于7个,那么这几个数就被作为生成哈希值的备用乘数了,那么这么多个该用那个更好呢?还有第2个原因
原因二:31可以被JVM优化
JVM里最有效的计算方式就是进行位运算了:
* 左移 << : 左边的最高位丢弃,右边补全0(把 << 左边的数据*2的移动次幂)。
* 右移 >> : 把>>左边的数据/2的移动次幂。
* 无符号右移 >>> : 无论最高位是0还是1,左边补齐0。
所以 : 31 * i = (i << 5) - i(左边 31*2=62,右边 2*2^5-2=62) - 两边相等,JVM就可以高效的进行计算啦。。。
哈希值通常用于比较对象/字符串/值等是否相等,如果2个字符串的哈希值不相等,那么这两个字符串肯定不相等(原始输入相等的话,算出来的哈希值肯定一样的)。但是,要证明两个字符串相等,除了哈希值要一样,还需要用equals方法判断(会出现哈希值冲突的情况)。