Java 哈希代码和聚合
对于如何为由其他类组成的类实现hashCode()方法,是否有标准的元算法或最佳实践: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() ^
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方法。您还可以对数组的元素递归地应用前面的规则,就像它们本身就是字段一样