Best implementation for hashCode method中接受的答案提供了一种看似很好的方法来查找哈希码。但我是Hash Codes的新手,所以我不知道该怎么做。
对于1),我选择的非零值是否重要? 1
是否与其他数字一样好,例如素数31
?
对于2),我是否将每个值添加到c?如果我有两个字段同时为long
,int
,double
等,该怎么办?
我是否在本课程中正确解读:
public MyClass{
long a, b, c; // these are the only fields
//some code and methods
public int hashCode(){
return 37 * (37 * ((int) (a ^ (a >>> 32))) + (int) (b ^ (b >>> 32)))
+ (int) (c ^ (c >>> 32));
}
}
答案 0 :(得分:15)
hashCode
值,因此它们是首选。hashCode
contract:
- 每当在执行Java应用程序期间多次在同一对象上调用它时,
hashCode
方法必须始终返回相同的整数,前提是不修改对象的等比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,此整数不需要保持一致。- 如果两个对象根据
equals(Object)
方法相等,则对两个对象中的每一个调用hashCode
方法必须生成相同的整数结果。- 如果根据
equals(java.lang.Object)
方法两个对象不相等,则不需要在两个对象中的每一个上调用hashCode方法必须产生不同的整数结果。但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。
有些算法可以被认为是不好的hashCode
实现,简单地添加属性值就是其中之一。原因是,如果您有一个包含两个字段的类,Integer
a ,Integer
b 和您的hashCode()
只是总结这些值,然后hashCode
值的分布高度依赖于实例存储的值。例如,如果 a 的大部分值在0-10之间且 b 在0-10之间,则hashCode
值在0-20之间。这意味着如果您将此类的实例存储在例如HashMap
多个实例将存储在同一个存储桶中(因为具有不同 a 和 b 值但具有相同总和的多个实例将放在同一个存储桶中)。这将对地图上的操作性能产生不良影响,因为在进行查找时,将使用equals()
比较存储桶中的所有元素。
关于算法,它看起来很好,它与Eclipse生成的非常类似,但它使用的是不同的素数,31而不是37:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (a ^ (a >>> 32));
result = prime * result + (int) (b ^ (b >>> 32));
result = prime * result + (int) (c ^ (c >>> 32));
return result;
}
答案 1 :(得分:5)
对于长值,已经存在一个行为良好的哈希码方法 - 不要重新发明轮子:
int hashCode = Long.valueOf((a * 31 + b) * 31 + c).hashCode();
乘以素数(在JDK类中通常为31)并累加总和是从多个数字创建“唯一”数字的常用方法。
Long的hashCode()方法使结果在int
范围内正确分布,使哈希“表现良好”(基本上是伪随机)。