Java 哈希代码和聚合

Java 哈希代码和聚合,java,language-agnostic,Java,Language Agnostic,对于如何为由其他类组成的类实现hashCode()方法,是否有标准的元算法或最佳实践: class A { B b; C c; ... } 如果我们假设B和C在实现它们的hashCode()时付出了一些努力,那么将as hashCode建立在B和C的基础上当然是个好主意。但如何最好地将它们结合起来呢 我这样问是因为某些操作显然不适合,如: class Naive { B b1, b2; public int hashCode() { return b1.hashCode() ^

对于如何为由其他类组成的类实现hashCode()方法,是否有标准的元算法或最佳实践:

class A { B b; C c;  ... }
如果我们假设B和C在实现它们的hashCode()时付出了一些努力,那么将
a
s hashCode建立在
B
C
的基础上当然是个好主意。但如何最好地将它们结合起来呢

我这样问是因为某些操作显然不适合,如:

class Naive {
   B b1, b2;
   public int hashCode() { return b1.hashCode() ^ b2.hashCode(); }
}

这将导致每个恰好有两个相等的
B
对象的朴素对象的哈希代码为0。

这是一种常见模式,一些Eclipse插件能够生成:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((b1 == null) ? 0 : b1.hashCode());
    result = prime * result + ((b2 == null) ? 0 : b2.hashCode());
    // repeat for other attributes you want to include...

    return result;
}
不要忘记相应地编写
equals()
方法…

Joshua Bloch的《有效Java》一书的第8项展示了一个很好的算法:

如果使用Java SE 7,还可以使用:

nwinkler的算法(实际上是Eclipse在使用Source>Generate hashcode and equals…功能时生成的算法)与Joshua Bloch在有效Java中描述的算法类似(如Puce的回答中所述)

其思想是组合为重要字段计算的哈希代码。使用奇数素数31可以导致乘法的jvm优化(转换为移位+减法)。请注意,必须将equals()中未使用的字段从该哈希代码计算中排除。您可以从计算中包含的字段中排除其值已计算的字段

为对象字段建议的hashcode计算只是递归调用其hashcode方法,前提是它不是null(在这种情况下,我们使用0),并且对象的equals()方法本身在equals()方法中递归调用。如果后者不是这样(equals对我们的对象字段进行更复杂的比较),建议的方法是构造一个规范表示并为其计算哈希代码

要计算基本字段的哈希代码,建议使用以下方法(注意,它们仍然必须通过执行result=result*prime+fieldHashCode组合到结果中):

  • 浮点:
    float.floatToIntBits(f)
  • int,byte,char,short:
    (int)f
  • long=>
    (int)(f^(f>>32))
  • 布尔值:
    (f?1:0)
  • double:
    longHash=double。double-tolongbits(f)
    然后使用
    (int)(longHash^(longHash>>32))
  • 数组:在Java1.5中,在arrays类中引入了一些hashCode方法。您还可以对数组的元素递归地应用前面的规则,就像它们本身就是字段一样

也许你可以发布算法本身,而不是仅仅发布一个指向一本书整个章节的链接?对不起,我没有时间这么做。我认为给出正确的方向就足够了,我不必复制其他来源。@Puce-没关系,我喜欢阅读PDF。只是不知道从哪里开始这个特定的主题。因此,你的回答确实很有帮助。