问题描述
这取决于您所说的“正确”。假设您正在使用hashCode()
所有相关的equals()
-defining字段,那么是的,它是“正确的”。但是,此类公式可能不会具有良好的分布,因此可能导致比其他情况更多的冲突,这将对性能产生不利影响。
这是来自 有效Java 2nd Edition条款 9 的引文:覆盖hashCode
时始终覆盖equals
尽管此项目中的配方产生了相当不错的哈希函数,但它没有产生最新的哈希函数,Java平台库也没有提供1.6版以上的哈希函数。编写这样的哈希函数是一个研究主题,数学家和计算机科学家最好去做。[…尽管如此]此项中描述的技术对于大多数应用来说应该是足够的。
评估拟议的哈希函数的性能可能不需要很多数学能力,但是为什么还要打扰呢?为什么不只是遵循经实践证明已足够的方法呢?
乔什·布洛赫(Josh Bloch)的食谱
- 将一个恒定的非零值(例如17)存储在
int
名为的变量中result
。 - 计算每个字段的
int
哈希码c
:- 如果该字段为
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。 - 如果该字段是数组,则将其视为每个元素都是一个单独的字段。如果数组字段中的每个元素都很重要,则可以使用
Arrays.hashCode
版本1.5中添加的方法之一。
- 如果该字段为
- 将哈希码
c
合并result
如下:result = 31 * result + c;
现在,该配方当然很复杂,但是幸运的是,由于java.util.Arrays.hashCode(Object[])
(并com.google.common.base.Objects
提供了一个方便的vararg变体),您不必每次都重新实现它。
@Override public int hashCode() {
return Arrays.hashCode(new Object[] {
myInt, //auto-Boxed
myDouble, //auto-Boxed
myRandomClass,
});
}
也可以看看
它 不 要求,如果两个对象根据是不相等的
equals(java.lang.Object)
方法,然后调用hashCode
在每个两个对象的方法必须产生不同的整数结果。但是, 程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。
解决方法
假设我有以下课程:
class ABC {
private int myInt = 1;
private double myDouble = 2;
private String myString = "123";
private SomeRandomClass1 myRandomClass1 = new ...
private SomeRandomClass2 myRandomClass2 = new ...
//pseudo code
public int myHashCode() {
return 37 *
myInt.hashcode() *
myDouble.hashCode() *
... *
myRandomClass.hashcode()
}
}
这是hashCode的正确实现吗?这不是我通常这样做的方式(我倾向于遵循有效的Java准则),但是我总是很想做类似上面的代码的诱惑。
谢谢