Java 中全部的类都继承自 Object 类,Object 类中有个返回 hashCode 的本地方法。java
public native int hashCode();
复制代码
在文档的注释中很清楚的说明了 hashCode 的做用,和它应该知足的一些要求。算法
做用:给一个对象返回一个 hashCode 值,这个值在 hash table 的数据结构中有重要的做用。例如,肯定放置在 hash table 哪一个索引位置,hash 冲突的频率。segmentfault
要求:数组
一般的 hashCode 生成方法是将对象的内存地址转换成一个整型数,这样就能为不一样的对象返回一个不同的 hashCode。可是这种方法不能知足上面的第二个条件,因此这种实现也不是 Java 语言所必须的实现方法。数据结构
String 类也是继承自 Object 类,它重写了 hashCode() 方法。优化
/** Cache the hash code for the string */
private int hash; // Default to 0
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;
}
复制代码
在 String 中计算的 hashCode 会存储在 hash 变量中,而且只会计算一次。由于 String 是 final 的,而且一个 String 对象被初始化后没法修改,因此它的 hashCode 不会变化。spa
for 循环计算 hashCode 的方法是根据如下式子:s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]。设计
31 是一个质数(Prime number),质数也称为素数。质数是大于 1 的天然数,且只能被 1 和其自己整除。code
选择 31 的缘由大概有如下几点:对象
一个数乘质数后的结果,只能被 1 、质数、乘数还有结果自己整除。计算 hashCode 选择一个优质质数能够下降 hash 的冲突率。
31 (2 << 5 - 1),在计算的过程当中能够被 JVM 优化。
相信第二点不少同窗都可以理解,如今解释一下第一点。
咱们列举一下 100 之内左右的质数:2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97。
从上面的质数中选择三个小中大质数:2,31,97。分析公式 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 中的每一项,都是一个数乘质数的平方项。因此咱们计算一下每一个质数的 n 次方,咱们选择 n = 5。那么结果以下:
质数 | 结果 |
---|---|
2 | 2^5 = 32 |
31 | 31^5 = 28,629,151 |
97 | 97^5 = 8,587,340,257 |
能够看到经过质数 2 计算后的 hashCode 值是一个比较小的值,而经过质数 97 计算后的 hashCode 是一个比较大的值,而 31 比较适中。
咱们能够认为 hashCode 的范围若过小,可能会增长 hash 冲突的几率。而计算 hashCode 的计算乘子太大容易致使整型数的溢出(这里并非说选择 31 不会致使溢出,是指一个致使溢出的速率),从而也会致使 hash 冲突的几率。31 能够有效的减轻这两点。
更详细的内容能够看一下 stackoverflow 上面的这个问题:Why does Java's hashCode() in String use 31 as a multiplier?
根据《Effective Java》第二版中的第 9 条,对于咱们本身编写的类,覆盖 equals 方法时须要覆盖 hashCode 方法。缘由在前面说过。
那么如何设计一个 hashCode 算法,书中设计了一个算法:
科普:为何 String hashCode 方法选择数字31做为乘子
Why does Java's hashCode() in String use 31 as a multiplier?
《Effective Java》