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");
}
Run Code Online (Sandbox Code Playgroud)
需要大约399 372纳秒.
for (int j = 0; j < 1000; j++) {
String s = "hello World";
}
Run Code Online (Sandbox Code Playgroud)
大约需要23 000纳秒.
为什么会有这么多的性能提升?内部是否有任何编译器优化?
pca*_*cao 40
在第一种情况下,在每次迭代中创建一个新对象,在第二种情况下,它始终是从String常量池中检索的同一对象.
在Java中,当你这样做时:
String bla = new String("xpto");
Run Code Online (Sandbox Code Playgroud)
您强制创建一个新的String对象,这会占用一些时间和内存.
另一方面,当你这样做时:
String muchMuchFaster = "xpto"; //String literal!
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
有了这一切,您可以找出这些Sysouts的结果:
false
false
true
Run Code Online (Sandbox Code Playgroud)
由于c
和d
是相同的对象,==
比较成立.