相对于JVM的字符串池,在Java中创建字符串的时间成本是多少?

xiozqbni  于 2022-11-07  发布在  Java
关注(0)|答案(6)|浏览(118)

Java有一个字符串池,因此在实际创建一个新字符串之前,我猜会检查是否已经存在相同的字符串,这个调用的成本是多少?
池是基于散列结构还是基于树结构?
在这两种情况下,我猜归结为字符串哈希代码的性能,因为搜索树使用哈希代码作为关键字?
我猜它大约是log n,其中n是堆中当前的字符串数。

zbwhf8kr

zbwhf8kr1#

this unofficial blog开始
Java虚拟机维护一个内部的字符串引用列表(唯一字符串池),以避免堆内存中出现重复的字符串对象。每当JVM从类文件加载字符串文字并执行时,它都会检查该字符串是否存在于内部列表中。如果它已经存在于列表中,则不会创建新的字符串,而是使用对现有字符串对象的引用。

JVM在内部对字符串文字执行这种类型的检查,但不对它通过'new'关键字创建的字符串对象执行这种类型的检查。可以使用String.intern()方法显式强制JVM对通过' new '关键字创建的字符串对象执行这种类型的检查。这将强制JVM检查内部列表并使用现有的字符串对象(如果已存在)。

envsm3lx

envsm3lx2#

没有检查一个新字符串是否已经在字符串池中,这就是为什么你不应该使用==来比较字符串的原因之一。
字符串池用于编译时已知的字符串。或者,如果您手动使用intern()并使用返回的示例。

4xy9mtcn

4xy9mtcn3#

每次在运行时动态创建String时,都会返回一个新的String示例。String池只包含String文本和String编译时常量,或者通过调用String.intern()显式添加到池中的String。

rkue9o1l

rkue9o1l4#

当JVM运行时,只有常量字符串(即硬编码)在字符串池中。

public class StringExample{
    private static final String CONSTANT = "Cannon Ball!!!"; // <- In the pool
    public void processStrings(String[] args){
                               //        ^--Assumed contents are variables, not in the pool
        String temp = "I'll wade in."; // <- In the pool
        StringBuilder sb = new StringBuilder(100);
        sb.append("I").append(" hate").append(" water.");  
        String dynamic = sb.toString(); //  <- Not in the pool.
        dynamic.intern(); // <- Now it's in the pool.

    }
}

所有动态字符串都在字符串池的外部。您可以通过调用String.intern()以编程方式将字符串添加到池中。
编辑:针对您的问题提出您的意见:当您遇到类似以下情况时:

public class StringExample{
   public static final String CONSTANT = "Just me.";
}
public class Foo{
   private String value = StringExample.CONSTANT;
}

在编译时,编译器只是将引用替换为硬编码字符串,因此这等效于执行

public class StringExample{
   public static final String CONSTANT = "Just me.";
}
public class Foo{
   private String value = "Just me.";
}
esyap4oy

esyap4oy5#

Java有一个字符串池,因此在实际创建一个新字符串之前,我猜会检查是否已经存在相同的字符串,这个调用的成本是多少?
这种情况只发生在字符串文本上,而不是你创建的字符串上。你可以调用String.intern()将它添加到池中,但必须在它被创建之后。
池是基于散列结构还是基于树结构?
这是一个固定大小的哈希Map,带有冲突的链表。我建议你不要过度使用它。因为它不能伸缩。
在这两种情况下,我猜归结为字符串哈希代码的性能,因为搜索树使用哈希代码作为关键字?
如果你需要一个字符串池,我建议你自己写一个。我有一个,它接受一个byte[]或一个CharSequence,比如一个StringBuilder,并池化字符串,所以它在90%的时间里不会创建对象(这是目标)
我猜它大约是log n,其中n是堆中当前的字符串数。
实际上是O(1),直到大约10,000,这是容量,之后它是O(n),这不是很大。
它如何池化/缓存文本,编译器是否使用对静态对象的引用来替换文本?-
编译器在给定的类文件中组合字符串文字,但JVM接受它并为整个JVM组合它们。

fcy6dtqo

fcy6dtqo6#

任何在编译时已知的字符串都被池化,这意味着下面的语句只创建一个字符串。(字符串文字是最明显的例子,但任何编译时常量字符串都被池化)

static final String a= "hello world";
static final String b= "hello world";
static final String c= "hello" + " world";

但是,在程序正常运行过程中创建的任何字符串都不会进入池,因此不存在此类检查,除非您显式调用.intern()

相关问题