为什么Java的String的hashCode()方法使用31作为乘数?

张开发
2026/4/16 9:36:17 15 分钟阅读

分享文章

为什么Java的String的hashCode()方法使用31作为乘数?
为什么Java的String的hashCode()方法使用31作为乘数在Java中String类的hashCode()方法被广泛用于哈希表、集合等数据结构中其核心算法是将字符串的每个字符依次乘以一个固定值31并累加。这个看似简单的设计背后隐藏着计算机科学中的精妙权衡。为什么偏偏选择31这个数字本文将从计算效率、哈希分布、历史沿革等角度揭开这一设计背后的逻辑。计算效率的优化31作为乘数在计算上具有显著优势。它是一个奇素数且恰好等于2的5次方减13132-1这种特性使得JVM可以通过位运算优化乘法操作。例如31*i可以转化为(i5)-i从而减少CPU时钟周期的消耗。在早期硬件性能有限的背景下这种优化对大规模字符串处理尤为重要。哈希冲突的平衡哈希函数的核心目标是减少冲突。31作为中等大小的素数既能避免像2这样的小素数导致的过度重复如ab和ba的哈希值相同又能防止过大的乘数造成数值溢出。实验表明31在英文字符集的分布测试中能有效分散哈希值降低冲突概率。历史与兼容性Java的设计者James Gosling曾提到31的选择部分源于历史惯例。早期编程语言如Pascal和Perl也采用类似策略。保持一致性有助于开发者理解和跨语言迁移。Java的早期版本已广泛依赖此实现后续版本为保持向后兼容性延续了这一设计。其他因素的考量31的另一个优势是其与字符集的适配性。ASCII字符范围是0-127Unicode基本平面字符也集中在低位31的乘法操作能较好地混合这些位的特征。31作为质数能避免与常见哈希表容量如2的幂次方产生公因数进一步减少冲突。总结来看31的选择并非偶然而是计算效率、哈希质量、历史实践等多方权衡的结果。尽管现代硬件性能提升但这一经典设计仍因其稳定性和普适性得以保留。理解这一细节能帮助开发者更深入地掌握Java集合框架的底层机制。

更多文章