在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
What is a best practice of writing hash function in java?
提问by Denys S.
采纳答案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 hashCode
when you override equals
":
这是Effective Java 2nd EditionItem 9的引用:“Always override hashCode
when 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
int
variable calledresult
- Compute an
int
hashcodec
for each fieldf
that definesequals
:- 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
, computeFloat.floatToIntBits(f)
- If the field is a
double
, computeDouble.doubleToLongBits(f)
, then hash the resultinglong
as in above - If the field is an object reference and this class's
equals
method compares the field by recursively invokingequals
, recursively invokehashCode
on the field. If the value of the field isnull
, 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.hashCode
methods added in release 1.5
- If the field is a
- Combine the hashcode
c
intoresult
as follows:result = 31 * result + c;
- 将一些恒定的非零值(例如 17)存储在
int
名为的变量中result
- 为定义的每个字段计算
int
哈希码:c
f
equals
- 如果字段是 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.hashCode
1.5 版中添加的方法之一
- 如果字段是 a
- 将哈希码组合
c
成result
如下: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...)
.