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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2738886/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 12:19:02  来源:igfitidea点击:

What is a best practice of writing hash function in java?

javahash

提问by Denys S.

I'm wondering what is the best practice for writing #hashCode() method in java. Good description can be found here. Is it that good?

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

采纳答案by Cesar

A great reference for an implementation of hashCode()is described in the book Effective Java. After you understand the theory behind generating a good hash function, you may check HashCodeBuilderfrom Apache commons lang, which implements what's described in the book. From the docs:

实现的重要参考hashCode()Effective Java一书中描述。在你理解了生成一个好的哈希函数背后的理论之后,你可以查看Apache commons lang 中的HashCodeBuilder,它实现了书中描述的内容。从文档:

This class enables a good hashCode method to be built for any class. It follows the rules laid out in the book Effective Java by Joshua Bloch. Writing a good hashCode method is actually quite difficult. This class aims to simplify the process.

此类可以为任何类构建良好的 hashCode 方法。它遵循 Joshua Bloch 在 Effective Java 一书中列出的规则。编写一个好的 hashCode 方法实际上是相当困难的。本课程旨在简化过程。

回答by Carl Manaster

It's good, as @leonbloy says, to understand it well. Even then, however, one "best" practice is to simply let your IDE write the function for you. It won't be optimal under some circumstances - and in some very rare circumstances it won't even be good - but for most situations, it's easy, repeatable, error-free, and as good (as a hash code) as it needs to be. Sure, read the docs and understand it well - but don't complicate it unnecessarily.

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

回答by polygenelubricants

Here's a quote from Effective Java 2nd Edition, Item 9: "Always override hashCodewhen you override equals":

这是Effective Java 2nd EditionItem 9的引用:“Always override hashCodewhen you override equals”:

While the recipe in this item yields reasonably good hash functions, it does not yield state-of-the-art hash functions, nor do Java platform libraries provide such hash functions as of release 1.6. Writing such hash functions is a research topic, best left to mathematicians and computer scientists. [... Nonetheless,] the techniques described in this item should be adequate for most applications.

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

Josh Bloch's recipe

乔什·布洛赫的食谱

  • Store some constant nonzero value, say 17, in an intvariable called result
  • Compute an inthashcode cfor each field fthat defines equals:
    • If the field is a boolean, compute (f ? 1 : 0)
    • If the field is a byte, char, short, int, compute (int) f
    • If the field is a long, compute (int) (f ^ (f >>> 32))
    • If the field is a float, compute Float.floatToIntBits(f)
    • If the field is a double, compute Double.doubleToLongBits(f), then hash the resulting longas in above
    • If the field is an object reference and this class's equalsmethod compares the field by recursively invoking equals, recursively invoke hashCodeon the field. If the value of the field is null, return 0
    • If the field is an array, treat it as if each element is a separate field. If every element in an array field is significant, you can use one of the Arrays.hashCodemethods added in release 1.5
  • Combine the hashcode cinto resultas follows: result = 31 * result + c;
  • 将一些恒定的非零值(例如 17)存储在int名为的变量中result
  • 为定义的每个字段计算int哈希码: cfequals
    • 如果字段是 a boolean,计算(f ? 1 : 0)
    • 如果字段是 a byte, char, short, int,计算(int) f
    • 如果字段是 a long,计算(int) (f ^ (f >>> 32))
    • 如果字段是 a float,计算Float.floatToIntBits(f)
    • 如果该字段是 a double,则计算Double.doubleToLongBits(f),然后将结果散列long如上
    • 如果该字段是一个对象引用并且该类的equals方法通过递归调用来比较该字段equals,则hashCode在该字段上递归调用。如果该字段的值为null,则返回 0
    • 如果该字段是一个数组,则将其视为每个元素都是一个单独的字段。如果数组字段中的每个元素都很重要,您可以使用Arrays.hashCode1.5 版中添加的方法之一
  • 将哈希码组合cresult如下:result = 31 * result + c;

Now, of course that recipe is rather complicated, but luckily, you don't have to reimplement it every time, thanks to java.util.Arrays.hashCode(Object[]).

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

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

As of Java 7 there is a convenient varargs variant in java.util.Objects.hash(Object...).

从 Java 7 开始,java.util.Objects.hash(Object...).