好hashCode()实现

在hashCode方法的Best实现中接受的答案给出了一种看似很好的方法来查找哈希码。 但我是Hash Codes的新手,所以我不知道该怎么做。

对于1),我选择的非零值是否重要? 1和其他数字一样好,例如素数31

对于2),我是否将每个值添加到c? 如果我有两个longintdouble等字段怎么办?


我是否在本课程中正确理解了它:

 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)); } } 

  1. 价值并不重要,它可以是你想要的任何东西。 素数将导致hashCode值的更好分布,因此它们是首选。
  2. 你没有必要添加它们,你可以自由地实现你想要的任何算法,只要它满足hashCode 合同 :
  • 每当在执行Java应用程序期间多次在同一对象上调用它时, hashCode方法必须始终返回相同的整数,前提是不修改对象上的equals比较中使用的信息。 从应用程序的一次执行到同一应用程序的另一次执行,该整数不需要保持一致。
  • 如果两个对象根据equals(Object)方法equals(Object) ,则对两个对象中的每一个调用hashCode方法必须生成相同的整数结果。
  • 如果两个对象根据equals(java.lang.Object)方法不相等,则不需要在两个对象中的每一个上调用hashCode方法必须生成不同的整数结果。 但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。

有些算法可以被认为是不好的hashCode实现,简单地添加属性值就是其中之一。 原因是,如果你有一个有两个字段的类, Integer aInteger b和你的hashCode()只是总结这些值,那么hashCode值的分布高度依赖于你的实例存储的值。 例如,如果a的大多数值在0-10和b之间在0-10之间,则hashCode值在0-20之间。 这意味着如果您将此类的实例存储在例如HashMap许多实例将存储在同一个存储桶中(因为具有不同ab值但具有相同总和的许多实例将放在同一个存储桶中)。 这将对地图上的操作性能产生不良影响,因为在进行查找时,将使用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; } 

对于长值,已经存在一个表现良好的哈希码方法 – 不要重新发明轮子:

 int hashCode = Long.valueOf((a * 31 + b) * 31 + c).hashCode(); 

乘以素数(在JDK类中通常为31)并累加总和是从多个数字创建“唯一”数字的常用方法。

Long的hashCode()方法保持结果在int范围内正确分布,使得哈希“表现良好”(基本上是伪随机的)。