Java HashMap put()实现。为什么不先查一下参考资料呢?

Java HashMap put()实现。为什么不先查一下参考资料呢?,java,standard-library,Java,Standard Library,具有put方法的实现,该实现具有: 在上面的代码中,为什么不首先进行引用检查(因为具有相同引用的两个对象将具有相同的hash和equals()) i、 例如: if ((k = e.key) == key) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } else if ( compare hash and equals) { // do s

具有put方法的实现,该实现具有:

在上面的代码中,为什么不首先进行引用检查(因为具有相同引用的两个对象将具有相同的hash和equals())

i、 例如:

if ((k = e.key) == key) {
    V oldValue = e.value;
    e.value = value;
    e.recordAccess(this);
    return oldValue;
} else if ( compare hash and equals) {
    // do something again with the value
}

这不会节省比较吗?

我不知道为什么,但一个天真的微基准表明,在Oracle的VM(Intel,32或64位)上,比较两个引用所需的时间大约是比较两个整数(如哈希代码)所需时间的四倍。我假设比较两个32位整数和两个地址指针在现代硬件上的运行时成本应该是相似的,但我可能只是没有考虑一些明显的问题

假设在大多数情况下不同的键具有不同的哈希代码,则在键之前比较哈希会为每个不正确的键节省75%的运行时间,并为正确的键增加25%的运行时间。如果这确实节省了整个运行时,当然取决于哈希映射表的确切内容和布局,但是Sun工程师显然认为这种变体在大多数情况下更好

用于基准测试的方法:

public static int c1(int a, int b, int iter) {
    int r = 0;
    while((iter--)>0) {
        if(a == b) {
            r++;
        }
    }
    return r;
}

public static int c2(Object a, Object b, int iter) {
    int r = 0;
    while((iter--)>0) {
        if(a == b) {
            r++;
        }
    }
    return r;
}
操作(整数比较)和(引用比较)使用相同的技术获得结果[,,]

两者在堆栈上都有准备好的值,并平等地使用它。所需操作之间不应有显著差异。两者都将在单CPU周期内完成

为了说明map可以将对象存储在同一个bucket中,必须有两条验证规则

  • 它们的哈希代码必须相等
  • 当x等于(y)时,必须返回true
我知道代码是如何反映这些规则的,我可以这样写

if(e.hash==hash&&key.equals(k))

为了满足映射要求,我们必须始终验证哈希和相等

因此,出于性能原因,零件
key.equals(k)
使用
(k=e.key)==key
进行了优化

((k=e.key)==key | | key.equals(k))


这个实现意味着对于映射,我们评估更多的散列和相等,然后引用相等。因此,这是预期的行为

这会在某些情况下保存比较。是的,我同意,它只会在某些情况下保存比较。请向Oracle建议您的修复方案。他们可能会将其应用到Java9中。您的建议只有在平均速度更快的情况下才是有益的。它平均速度快吗?
if(k=e.key)==key){
应该是
if(k=e.key)==key){
请给我们看一下基准测试。看看你的代表,你应该能够写一个有效的基准测试,但为了确保,你知道:)@MartijnCourteaux:当然。请显示更多的代码。我认为这段代码在自动优化代码时已经非常可疑。基准测试对各种小事情都非常敏感你忘了做。例如:这些方法的错误使用可能会导致你的方法什么都不做。我的意思是,实际上什么都不做。编译器可能只是优化你的整个方法调用。我不确定JIT是否会在通过阈值后优化比较。有人能证实这一点吗?@Martijn:当然有可能假设优化器在某个点上决定条件(a==b)永远不会改变,但只要c1和c2之间的运行时比率保持相对恒定,与迭代次数无关,我至少会首先假设差异是由比较整数而不是引用引起的。
public static int c1(int a, int b, int iter) {
    int r = 0;
    while((iter--)>0) {
        if(a == b) {
            r++;
        }
    }
    return r;
}

public static int c2(Object a, Object b, int iter) {
    int r = 0;
    while((iter--)>0) {
        if(a == b) {
            r++;
        }
    }
    return r;
}