Java字符串中的hashCode实现

7

好奇,在String的hashCode实现中,为什么需要在hashCode实现中创建额外的引用(版本1.8.0_65):

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

考虑到value是final的,而且只在构造函数中创建(即线程安全),我们为什么需要在这里使用变量val[]的引用呢?

也就是说,这样会起作用吗:

public int hashCode() {
    if (hash == 0 && value.length > 0) {
        int h = 0;
        for (int i = 0; i < value.length; i++) {
            h = 31 * h + value[i];
        }
        hash = h;
    }
    return hash;
}

除了将值从堆复制到栈以加快速度外,这也涉及到@zapl在评论中描述的竞争条件。在他的评论之前,这对我来说并不明显。


这不是关于避免 getopt 的问题。这是关于数据竞争的问题,因为 hash 既不是 volatile 也没有被同步。这就是为什么他们不会 return hash(你读取的值没有保证)。 - zapl
我不同意这个说法。哈希是int类型(不是long类型),即所有操作都是原子性的,在最坏的情况下,你只会计算两次,这可能会发生在两种情况下。 - Konstantin Kulagin
抱歉,注释有点乱。但是即使我们不考虑“hash”变量,为什么要复制最终的“value”呢? :) - Konstantin Kulagin
1
我猜这确实避免了字段的重复加载。现代JVM可能不需要,但该方法也使用相当古老的代码。例如,http://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/geninfo/diagnos/underst_jit.html#wp1077986显示jrockit(自Java 7以来已与hotspot合并)肯定可以为您本地缓存字段引用(这只是它执行的较简单的操作之一)。 - zapl
实际上,我也想将您的答案标记为正确答案,但评论无法实现此功能。再次感谢您的帮助! - Konstantin Kulagin
显示剩余3条评论
1个回答

1
似乎意图是将 hashvalue 句柄明确地放在堆栈上。

链接到重复的问题已经有答案了。 - ControlAltDel
是的,Tunaki标记了正确的重复项。他们不想要一个用于重复获取数据的指令。您可以将其放在堆上。 - TheLostMind
他们关心的是那些稍微慢一点的访问:P - TheLostMind

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接