为什么字符串中的Java的hashCode()使用31作为乘数?

2022-08-31 04:19:23

根据 Java 文档,对象的哈希代码计算如下:String

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

使用算术,其中是字符串的第i个字符,是字符串的长度,并指示幂。ints[i]n^

为什么31被用作乘数?

我理解乘数应该是一个相对较大的素数。那么为什么不是29岁,37岁,甚至97岁呢?


答案 1

根据Joshua Bloch的《Effective Java》(这本书不能被推荐,我买了这本书,这要归功于对stackoverflow的持续提及):

之所以选择值 31,是因为它是奇数素数。如果它是偶数并且乘法溢出,信息将丢失,因为乘以2相当于移位。使用素数的优势不太明显,但它是传统的。31 的一个很好的属性是乘法可以被移位和减法替换以获得更好的性能:。现代 VM 会自动执行此类优化。31 * i == (i << 5) - i

(摘自第 3 章第 9 项:覆盖等于时始终覆盖哈希码,第 48 页)


答案 2

Goodrich 和 Tamassia 根据超过 50,000 个英语单词(形成为 Unix 的两个变体中提供的单词列表的并集)进行计算,使用常量 31、33、37、39 和 41 在每种情况下产生的碰撞次数少于 7 次。这可能是许多Java实现选择此类常量的原因。

请参阅 Java 中的数据结构和算法的第 9.2 节哈希表(第 522 页)。