StackOverflow多次询问此问题,但没有一个基于性能。
在 Effective Java 一书中,它给出了
如果
String s = new String("stringette");
出现在循环或循环中 经常调用的方法,可以创建数百万个String实例 不必要的。改进版只是以下内容:
String s = "stringette";
此版本使用单个String实例,而不是 每次执行时都会创建一个新的。
所以,我尝试了两者,并在性能方面发现了显着的改进:
for (int j = 0; j < 1000; j++) {
String s = new String("hello World");
}
需要 399 372 纳秒。
for (int j = 0; j < 1000; j++) {
String s = "hello World";
}
需要 23 000 纳秒。
为什么会有如此多的性能提升?里面发生了编译器优化吗?
答案 0 :(得分:39)
在第一种情况下,在每次迭代中都会创建一个新对象,在第二种情况下,它始终是从String常量池中检索的同一个对象。
在Java中,当你这样做时:
String bla = new String("xpto");
你强制创建一个新的String对象,这需要一些时间和内存。
另一方面,当你这样做时:
String muchMuchFaster = "xpto"; //String literal!
String只会在第一次创建(一个新对象),并且会被缓存在String
常量池中,因此每次以它的字面形式引用它时,你都会得到它完全相同的对象,速度惊人。
现在您可能会问......如果代码中的两个不同点检索相同的文字并进行更改,会不会出现问题?!
不,因为您可能非常清楚,Java中的字符串是不可变的!因此,任何可以改变String的操作都会返回一个新的String,并保留对同一文字的任何其他引用。
这是不可变数据结构的优势之一,但这完全是另一个问题,我会写几篇关于这个主题的文章。
修改强>
只是澄清一下,常量池不是String类型所独有的,您可以在这里阅读更多相关信息,或者google for Java常量池。
http://docs.oracle.com/javase/specs/jvms/se7/jvms7.pdf
另外,你可以做一点点测试来推动这一点:
String a = new String("xpto");
String b = new String("xpto");
String c = "xpto";
String d = "xpto";
System.out.println(a == b);
System.out.println(a == c);
System.out.println(c == d);
有了这一切,你可以找出这些Sysouts的结果:
false
false
true
由于c
和d
是同一个对象,因此==
比较成立。
答案 1 :(得分:3)
性能差异实际上要大得多:HotSpot可以轻松编译整个循环
for (int j = 0; j < 1000; j++)
{String s="hello World";}
不存在所以运行时是一个稳定的0.然而,只有在JIT编译器启动后才会发生这种情况。这就是 warmup 的用途,是对JVM上的任何内容进行微基准测试时的强制性过程。
这是我运行的代码:
public static void timeLiteral() {
for (int j = 0; j < 1_000_000_000; j++)
{String s="hello World";}
}
public static void main(String... args) {
for (int i = 0; i < 10; i++) {
final long start = System.nanoTime();
timeLiteral();
System.out.println((System.nanoTime() - start) / 1000);
}
}
这是一个典型的输出:
1412
38
25
1
1
0
0
1
0
1
你可以很快观察到JIT的效果。
请注意,我不会在内部方法中迭代一千个,而是一个十亿次次。
答案 2 :(得分:1)
已经回答第二个从字符串池中检索实例(记住字符串是不可变的)。
此外,您应该检查intern()方法,该方法允许您将新的String()放入池中,以防您在运行时不知道字符串的常量值:例如:
String s = stringVar.intern();
或
new String(stringVar).intern();
我将添加其他事实,您应该知道除了String对象之外,池中还存在更多信息(哈希码):这样可以在相关数据Strtuctures中通过String快速搜索hashMap(而不是每次都重新创建哈希码)
答案 3 :(得分:0)
JVM维护一个对文字唯一String对象的引用池。在新的String示例中,您将使用每个文本的实例包装文字。
请参阅http://www.precisejava.com/javaperf/j2se/StringAndStringBuffer.htm