9

hashCode 方法的最佳实现中的公认答案提供了一种看似不错的查找哈希码的方法。但我是哈希码的新手,所以我不太清楚该怎么做。

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

对于 2),我是否将每个值添加到 c?如果我有两个字段都是 a 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));
    }
}
4

2 回答 2

18
  1. 价值并不重要,它可以是任何你想要的。素数将导致更好的hashCode值分布,因此它们是首选。
  2. 您不必添加它们,您可以自由实现您想要的任何算法,只要它符合hashCode 合同
  • 在 Java 应用程序执行期间,只要在同一个对象上多次调用该方法,该hashCode方法必须始终返回相同的整数,前提是没有修改对象上的 equals 比较中使用的信息。该整数不需要从应用程序的一次执行到同一应用程序的另一次执行保持一致。
  • 如果根据方法两个对象相等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;
}
于 2013-05-18T23:14:02.923 回答
6

对于 long 值,已经存在一种行为良好的哈希码方法 - 不要重新发明轮子:

int hashCode = Long.hashCode((a * 31 + b) * 31 + c); // Java 8+

int hashCode = Long.valueOf((a * 31 + b) * 31 + c).hashCode() // Java <8

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

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

于 2013-05-18T23:30:18.307 回答