Is the hashcode of a Java String created when the String is created, or only at the first call for hashcode?

huangapple go评论71阅读模式
英文:

Is the hashcode of a Java String created when the String is created, or only at the first call for hashcode?

问题

问题很简单。

字符串的哈希码是何时计算的?

  1. 当字符串创建时,哈希码也会被计算,并且在构建后始终以O(1)的时间准备好。
  2. 哈希码仅在第一次调用hashCode方法时计算,并在随后的所有调用中以O(1)的时间准备好。
  3. 每次调用hashCode方法时都会计算哈希码。

选项1似乎合理,因为字符串是不可变的。给定字符串的哈希码永远不会更改。但是,这会减慢字符串的创建速度,所以选项2也似乎合理。选项3似乎愚蠢且浪费时间,但可以节省空间,因为哈希码不会被存储。也可能有一些逻辑上的原因,使选项3成为最佳方法,我没有考虑到。

非常感谢您提前的回答。

英文:

My question is quite simple.

When is the hashcode for a String calculated?

  1. When the String is created, the hashcode is also computed, and always ready in O(1) after construction
  2. The hashcode is computed only the first time the hashCode method is called and is ready in O(1) time for all subsequent calls
  3. The hashcode is computed each time the hashCode method is called

Option 1 seems reasonable because Strings are immutable. The hashcode for a given string will never change. But, this slows down the creation of strings, so it also seems reasonable that option 2 would be used. Option 3 seems silly and a waste of time, but saves on space because the hashcode isn't being stored. There may also be some logical reason that Option 3 is the best approach that I'm not thinking about.

Thanks so much in advance

答案1

得分: 3

选项2。第一次调用hashCode时计算并存储在私有字段中。

在OpenJDK 8中,它看起来像这样:

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;
}

可以在以下链接中找到更多信息:
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/String.java#l1452

事实上,如果查看String类具有哪些字段,您可以看到它有一个名为hash的私有整数。

System.out.println(String.class.getDeclaredFields());

输出包括:

{ ... private int java.lang.String.hash ... }
英文:

Option 2. It's calculated the first time hashCode is called and stored in a private field.

In OpenJDK 8 it looks like this:

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

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

http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/java/lang/String.java#l1452

In fact, if you take a look at what fields String has, you can see it has a private int called hash.

System.out.println(String.class.getDeclaredFields());

output includes

{ ... private int java.lang.String.hash ... }

答案2

得分: 3

From the source code JDK 14:

   /** Cache the hash code for the string */
    private int hash; // Default to 0


    @HotSpotIntrinsicCandidate
    public String(String original) {
        this.value = original.value;
        this.coder = original.coder;
        this.hash = original.hash;
    }

And then:

    public int hashCode() {
        // The hash or hashIsZero fields are subject to a benign data race,
        // making it crucial to ensure that any observable result of the
        // calculation in this method stays correct under any possible read of
        // these fields. Necessary restrictions to allow this to be correct
        // without explicit memory fences or similar concurrency primitives is
        // that we can ever only write to one of these two fields for a given
        // String instance, and that the computation is idempotent and derived
        // from immutable state
        int h = hash;
        if (h == 0 && !hashIsZero) {
            h = isLatin1() ? StringLatin1.hashCode(value)
                           : StringUTF16.hashCode(value);
            if (h == 0) {
                hashIsZero = true;
            } else {
                hash = h;
            }
        }
        return h;
    }
英文:

From the source code JDK 14

   /** Cache the hash code for the string */
    private int hash; // Default to 0


    @HotSpotIntrinsicCandidate
    public String(String original) {
        this.value = original.value;
        this.coder = original.coder;
        this.hash = original.hash;
    }

And then

    public int hashCode() {
        // The hash or hashIsZero fields are subject to a benign data race,
        // making it crucial to ensure that any observable result of the
        // calculation in this method stays correct under any possible read of
        // these fields. Necessary restrictions to allow this to be correct
        // without explicit memory fences or similar concurrency primitives is
        // that we can ever only write to one of these two fields for a given
        // String instance, and that the computation is idempotent and derived
        // from immutable state
        int h = hash;
        if (h == 0 &amp;&amp; !hashIsZero) {
            h = isLatin1() ? StringLatin1.hashCode(value)
                           : StringUTF16.hashCode(value);
            if (h == 0) {
                hashIsZero = true;
            } else {
                hash = h;
            }
        }
        return h;
    }

</details>



huangapple
  • 本文由 发表于 2020年8月4日 04:00:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/63236192.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定