在java中编写哈希函数的最佳实践是什么?

时间:2010-04-29 16:10:02

标签: java hash

我想知道在java中编写#hashCode()方法的最佳实践是什么。 可以找到好的描述here。这样好吗?

3 个答案:

答案 0 :(得分:52)

以下是来自 Effective Java 2nd Edition 的引用,第9项:“覆盖hashCode时始终覆盖equals”:

  

虽然这个项目中的配方产生了相当好的散列函数,但它不会产生最先进的散列函数,Java平台库也不提供1.6版本的散列函数。编写这样的哈希函数是一个研究课题,最好留给数学家和计算机科学家。 [...尽管如此,]此项目中描述的技术应该适用于大多数应用程序。

Josh Bloch的食谱

  • 在名为int
  • result变量中存储一些常量非零值,例如17
  • 为定义int的每个字段c计算f哈希码equals
    • 如果字段为boolean,请计算(f ? 1 : 0)
    • 如果字段为byte, char, short, int,请计算(int) f
    • 如果字段为long,请计算(int) (f ^ (f >>> 32))
    • 如果字段为float,请计算Float.floatToIntBits(f)
    • 如果该字段为double,请计算Double.doubleToLongBits(f),然后对生成的long进行哈希处理,如上所述
    • 如果该字段是对象引用,并且此类的equals方法通过递归调用equals来比较字段,则在该字段上递归调用hashCode。如果字段的值为null,则返回0
    • 如果字段是数组,则将其视为每个元素都是单独的字段。如果数组字段中的每个元素都很重要,则可以使用版本1.5中添加的Arrays.hashCode方法之一
  • 将哈希码c合并到result中,如下所示:result = 31 * result + c;

现在,当然,这个配方相当复杂,但幸运的是,你不必每次都重新实现它,感谢java.util.Arrays.hashCode(Object[])

@Override public int hashCode() {
    return Arrays.hashCode(new Object[] {
           myInt,    //auto-boxed
           myDouble, //auto-boxed
           myString,
    });
}

从Java 7开始,java.util.Objects.hash(Object...)中有一个方便的varargs变体。

答案 1 :(得分:21)

hashCode()一书中介绍了{{1}}实施的绝佳参考。在了解了生成良好哈希函数背后的理论之后,您可以从Apache commons lang中检查Effective Java,它实现了本书中描述的内容。来自文档:

  

这个类启用了一个好的hashCode   为任何类构建的方法。它   遵循书中规定的规则   约书亚布洛赫的有效Java。   编写一个好的hashCode方法是   实际上相当困难。这个班   旨在简化流程。

答案 2 :(得分:0)

正如@leonbloy所说,好好理解它。然而,即便如此,一个“最佳”的做法是简单地让IDE为您编写功能。在某些情况下它不会是最佳的 - 在一些非常罕见的情况下它甚至都不会好 - 但在大多数情况下,它很容易,可重复,没有错误,并且像它需要一样好(作为哈希码)成为。当然,阅读文档并理解它 - 但不要不必要地使它复杂化。