【问题标题】:Why do we use number 31 while calculating hashcode [duplicate]为什么我们在计算哈希码时使用数字 31 [重复]
【发布时间】:2020-02-26 03:06:37
【问题描述】:

我已经开始学习Collections。因此,当我们使用 eclipse 生成 hashcode 时,下面是该方法中存在的公式:

        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        result = prime * result + ((pin == null) ? 0 : pin.hashCode());

我搜索并发现由于31odd prime,我们在计算hashcode 时使用它。乘以素数可以很好地分布散列码。但是没有遇到任何关于我们为什么使用上述公式以及为什么使用 31 的具体/外行解释。有人可以帮忙详细说明乘以 31 究竟是如何提供更好的哈希码分布的吗?

【问题讨论】:

  • 这个想法是每次覆盖hashCode时都选择一个不同的奇质数,至于为什么是奇质数;它可以更好地在哈希桶中分配密钥。基本上,这是一个重要的实现细节。
  • 不仅是素数,还是Mersenne prime,即2^5 - 1 = 11111b,表示重复操作会保留更多位信息。它只是一个方便的数字,具有合理的平均性能。
  • @ElliottFrisch 谢谢,我已经编辑了问题
  • @chrylis-onstrike-,太棒了!!。可以作为答案发布。
  • 这能回答你的问题吗? Why does Java's hashCode() in String use 31 as a multiplier? 只需键入“java hash 31”即可将其作为第一个结果。

标签: java collections


【解决方案1】:

来自 Joshua Bloch,Effective Java,第 3 章,第 9 项

选择值 31 是因为它是一个奇数素数。如果它是偶数并且乘法溢出,则信息将丢失,因为乘以 2 相当于移位。使用素数的优势不太明显,但它是传统的。 31 的一个很好的特性是乘法可以用移位和减法代替以获得更好的性能:31 * i == (i

一些关于乘法的词可以用移位代替。在二进制代数中,乘以 2 是非常简单的操作。您只需要将数字左移并在末尾添加 0。 4*2 = b100

同样的逻辑也适用于除法:8/4 = 8/2^2 = b1000 >> 2 = b10 = 2

【讨论】:

    猜你喜欢
    • 2013-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    • 1970-01-01
    • 2017-02-04
    • 2010-09-16
    相关资源
    最近更新 更多