提问者:小点点

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


根据这篇博客文章,HashMap在已经检索到的hashCode上重新调用它自己的< code>hashCode()(称为< code>hash())实现。

如果key不为null,那么它将在key对象上调用哈希函数,参见上面方法中的第4行,即key.hashCode(),所以key.hashCode()返回hashValue后,第4行看起来像

int hash=hash(hashValue)

现在,它将返回的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;
}

}

共1个答案

匿名用户

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

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

至于为什么散列代码需要改进,请阅读该方法的javadoc:

计算密钥.哈希码()并将哈希的较高位传播(XOR)到较低位。由于该表使用二次幂掩码,因此仅在当前掩码上方的位上变化的哈希集将始终发生冲突。(已知示例包括一组 Float 键,这些键在小表中保存连续的整数。因此,我们应用了一个转换,将更高位的影响向下传播。在速度、效用和位传播质量之间需要权衡。因为许多常见的哈希集已经合理地分布了(所以不会从传播中受益),并且因为我们使用树来处理箱中的大量冲突,所以我们只是以最便宜的方式XOR一些移动位,以减少系统损失,以及合并最高位的影响,否则这些最高位永远不会用于索引计算,因为表边界。