HashMap为什么以及如何拥有自己的hashCode()内部实现,称为hash()?

根据这篇博客文章 ,HashMap在已经检索到的哈希码上重新调用自己的hashCode() (称为hash() )。

如果key不为null,则会调用key对象的hashfunction,参见上面方法中的第4行,即key.hashCode(),所以在key.hashCode()返回hashValue后,第4行看起来像

int hash = hash(hashValue)

现在,它将返回的hashValue应用到它自己的散列函数中。

我们可能想知道为什么我们使用hash(hashValue)再次计算hashvalue。 答案是,它防御质量差的哈希>函数。

HashMap能否准确地重新分配哈希码? HashMap可以存储对象,但它无法访问为其分配hashCode对象的逻辑。 例如, hash()无法集成以下hashCode()实现背后的逻辑:

 public class Employee { protected long employeeId; protected String firstName; protected String lastName; public int hashCode(){ return (int) employeeId; } } 

hash()从实际的哈希码中派生出“改进的”哈希码,因此相等的输入总是相等的输出(来自jdk1.8.0_51):

 static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } 

至于哈希代码需要改进的原因,请阅读方法的javadoc:

计算key.hashCode()并将散列(XOR)更高的散列位降低。 因为该表使用2次幂掩模,所以仅在当前掩码之上的位中变化的散列集将始终发生冲突。 (在已知的例子中是在小表中保存连续整数的浮点键集。)因此我们应用一个向下扩展高位比特影响的变换。 在速度,效用和比特扩展质量之间存在权衡。 因为许多常见的哈希集合已经合理分布(因此不会受益于传播),并且因为我们使用树来处理容器中的大量冲突,所以我们只是以最便宜的方式对一些移位的位进行异或,以减少系统损失,以及由于表格边界而包含最高位的影响,否则这些位将永远不会用于索引计算。