Java有一个字符串池,因此在实际创建一个新字符串之前,我想有一个检查是否已经存在相同的字符串,这个调用的成本是多少?
池是基于哈希还是基于树的结构?
在这两种情况下,我想归结为字符串哈希码的性能,因为搜索树使用哈希码作为键?
我猜它关于 log n,其中 n 是当前堆上的字符串数。
Java 虚拟机维护一个内部字符串引用列表(唯一字符串池),以避免堆内存中重复的字符串对象。每当 JVM 从类文件加载字符串文字并执行时,它都会检查该字符串是否存在于内部列表中。如果它已经存在于列表中,那么它不会创建新的字符串,而是使用对现有字符串对象的引用。
JVM 会在内部对字符串字面量进行这种类型的检查,但不会对它通过 'new' 关键字创建的字符串对象进行检查。
new
您可以显式强制 JVM 对通过 ' ' 关键字 usingString.intern()
方法创建的 String 对象进行此类检查。这会强制 JVM 检查内部列表并使用现有的 String 对象(如果它已经存在)。
当 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.";
}
没有检查新字符串是否已经在字符串池中,这是您不应该使用==
比较字符串的原因之一。
字符串池用于在编译时已知的字符串。或者,如果您手动使用intern()
并使用返回的实例。
每次在运行时动态创建 String 时,都会返回一个新的 String 实例。字符串池仅包含字符串文字和字符串编译时常量,或通过调用明确添加到池中的字符串String.intern()
。
任何可以在编译时知道的字符串都会被池化,这意味着下面只创建一个字符串。(字符串文字是最明显的例子,但任何编译时常量字符串都会被汇集)
static final String a= "hello world";
static final String b= "hello world";
static final String c= "hello" + " world";
但是,在程序正常运行期间创建的任何字符串都不会被池化,因此除非您明确调用,否则不存在此类检查.intern()
Java有一个字符串池,因此在实际创建一个新字符串之前,我想有一个检查是否已经存在相同的字符串,这个调用的成本是多少?
这仅适用于字符串文字,而不是您创建的字符串。您可以调用 String.intern() 将其添加到池中,但只能在创建之后。
池是基于哈希还是基于树的结构?
它是一个固定大小的哈希映射,带有用于冲突的链表。我建议你不要过度使用它。因为它没有缩放。
在这两种情况下,我想归结为字符串哈希码的性能,因为搜索树使用哈希码作为键?
如果你需要一个字符串池,我建议你自己写一个。我有一个需要一个byte[]
或一个CharSequence
这样的 StringBuilder 并将 String 池化,因此它不会在大约 90% 的时间内创建对象(即目标)
我猜它关于 log n,其中 n 是当前堆上的字符串数。
实际上是 O(1) 到大约 10,000 这是容量,之后是 O(n) 这不是很大。
它如何汇集/缓存文字,编译器是否将文字替换为对静态的引用?–
编译器在给定的类文件中组合字符串文字,但 JVM 接受它并将它们组合用于整个 JVM。