我们如何决定集合的hashCode()方法的最佳实现(假设equals方法已被正确重写)?


当前回答

我在arrays . deephashcode(…)周围使用了一个小包装器,因为它可以正确地处理作为参数提供的数组

public static int hash(final Object... objects) {
    return Arrays.deepHashCode(objects);
}

其他回答

只是一个快速的注释,以完成其他更详细的答案(在代码方面):

如果我考虑如何在java中创建哈希表的问题,特别是jGuru FAQ条目,我相信可以判断哈希代码的其他标准是:

同步(算法是否支持并发访问)? 失败安全迭代(算法是否检测到迭代过程中发生变化的集合) 空值(哈希码是否支持集合中的空值)

首先确保equals被正确实现。摘自一篇IBM DeveloperWorks文章:

对称性:对于两个参考,a和b,当且仅当b等于(a)时,a等于(b) 自反性:对于所有非空引用,a.equals(a) 及物性:如果a等于(b) b等于(c),那么a等于(c)

然后确保它们与hashCode的关系尊重联系人(来自同一篇文章):

与hashCode()的一致性:两个相等的对象必须具有相同的hashCode()值

最后,一个好的哈希函数应该努力接近理想的哈希函数。

由于您特别要求集合,我想添加一个其他答案还没有提到的方面:HashMap不期望它们的键在添加到集合后改变它们的hashcode。会破坏整个目的…

这里有一个非常严重的bug。

Zam obj1 = new Zam("foo", "bar", "baz");
Zam obj2 = new Zam("fo", "obar", "baz");

同样的hashcode

你可能想要

public int hashCode() {
    return (getFoo().hashCode() + getBar().hashCode()).toString().hashCode();

(现在你能在Java中直接从int获取hashCode吗?我认为它做了一些自动铸造。如果是这种情况,跳过toString,它很难看。)

最好的实现?这是一个很难回答的问题,因为这取决于使用模式。

Josh Bloch的Effective Java在第8项(第二版)中提出了几乎所有情况下合理的良好实现。最好的办法是去查一下,因为作者在那里解释了为什么这种方法是好的。

简短的版本

Create a int result and assign a non-zero value. For every field f tested in the equals() method, calculate a hash code c by: If the field f is a boolean: calculate (f ? 0 : 1); If the field f is a byte, char, short or int: calculate (int)f; If the field f is a long: calculate (int)(f ^ (f >>> 32)); If the field f is a float: calculate Float.floatToIntBits(f); If the field f is a double: calculate Double.doubleToLongBits(f) and handle the return value like every long value; If the field f is an object: Use the result of the hashCode() method or 0 if f == null; If the field f is an array: see every field as separate element and calculate the hash value in a recursive fashion and combine the values as described next. Combine the hash value c with result: result = 37 * result + c Return result

这将导致在大多数使用情况下哈希值的适当分布。