昨天在群里跟人讨论关于String累加的问题,貌似没有人能特别准确的知道是一个什么样的情况,今天我通过jclasslib (PS:从[url]http://zangxt.iteye.com/[/url]搞到的好东西)来检测一下编译器是如何进行字符串累加的,我们先写一段代码:
很简单,貌似网上也能给出一个大概的结论,但是我们还是亲手看一下编译后的代码:
[img]http://francis-xjl.iteye.com/upload/picture/pic/76646/a54d62d3-0dd1-355f-8e5e-1f027dc42ad9.jpg[/img]
我们可以看到上面的程序被编译成了22行的代码,我们注意看一下第6行到第18行,这是整个for循环所执行的代码,我们会很明显的看到,每次循环都会执行第6行的代码,也就是每次都会新建了一个StringBuilder对象,这多么浪费性能啊。
这就很明显了,每一次字符串的拼接,编译器都是通过新建StringBuilder对象来完成的。
哎,如果编译器足够智能,将新建StringBuilder对象放到循环之外,就不用我们去操心性能问题,但是,貌似目前编译器还办不到。所以我们手动的新建StringBuilder是比较好的方案:
为了确定是否真的达到效果,我们来看一下这次编译后的代码:
[img]http://francis-xjl.iteye.com/upload/picture/pic/76648/0e747ae2-f4a3-34a7-b4a1-c80dbb26fb49.jpg[/img]
这次循环的代码是在11~18行,而创建StringBuilder对象是在第三步执行。这样就避免了编译器会每个循环都新建一个StringBuilder对象了。比较好的习惯就是当连接字符串操作比较多的时候直接手动新建StringBuilder对象.
那有人可能会问了,String的每次拼接都是利用创建StringBilder对象来处理么? 实践乃检验真理的唯一方法:
先写代码:
然后再看一下编译后的结果,由于比较长,我分成两张图片:
[img]http://francis-xjl.iteye.com/upload/picture/pic/76650/3ba0e801-9bed-371c-a891-755160f1964b.jpg[/img]
[img]http://francis-xjl.iteye.com/upload/picture/pic/76652/d35d2dd4-c719-333b-b5f6-43decd40fb88.jpg[/img]
很显然,有四个new StringBuilder操作。基本可以得出结论:需要字符串连接的时候,如果没有可用的对应的StringBuilder就会去新建。因此字符串操作还是推荐自己手动去new StringBuilder,不能依赖编译器的优化。
当然会有很多其它情况,比如我在第三行代码后面加一个c+=a;a+=b;会产生什么样的情况呢?实践乃检验真理的唯一方法,自己去检测吧~~ :lol:
package francis;
public class TestString {
public static void main(String[]args) {
String s = "";
for(int i = 0; i < 1000; i++) {
s += i;
}
System.out.println(s);
}
}
很简单,貌似网上也能给出一个大概的结论,但是我们还是亲手看一下编译后的代码:
[img]http://francis-xjl.iteye.com/upload/picture/pic/76646/a54d62d3-0dd1-355f-8e5e-1f027dc42ad9.jpg[/img]
我们可以看到上面的程序被编译成了22行的代码,我们注意看一下第6行到第18行,这是整个for循环所执行的代码,我们会很明显的看到,每次循环都会执行第6行的代码,也就是每次都会新建了一个StringBuilder对象,这多么浪费性能啊。
这就很明显了,每一次字符串的拼接,编译器都是通过新建StringBuilder对象来完成的。
哎,如果编译器足够智能,将新建StringBuilder对象放到循环之外,就不用我们去操心性能问题,但是,貌似目前编译器还办不到。所以我们手动的新建StringBuilder是比较好的方案:
package francis;
public class TestString {
public static void main(String[]args) {
String s = "";
StringBuilder sb = new StringBuilder(s);
for(int i = 0; i < 1000; i++) {
sb.append(i);
}
s = sb.toString();
System.out.println(s);
}
}
为了确定是否真的达到效果,我们来看一下这次编译后的代码:
[img]http://francis-xjl.iteye.com/upload/picture/pic/76648/0e747ae2-f4a3-34a7-b4a1-c80dbb26fb49.jpg[/img]
这次循环的代码是在11~18行,而创建StringBuilder对象是在第三步执行。这样就避免了编译器会每个循环都新建一个StringBuilder对象了。比较好的习惯就是当连接字符串操作比较多的时候直接手动新建StringBuilder对象.
那有人可能会问了,String的每次拼接都是利用创建StringBilder对象来处理么? 实践乃检验真理的唯一方法:
先写代码:
package francis;
public class TestString {
public static void main(String[]args) {
String a = "a" + "b" + "c";
String b = a + "b";
String c = a + b;
System.out.println(a + b + c);
}
}
然后再看一下编译后的结果,由于比较长,我分成两张图片:
[img]http://francis-xjl.iteye.com/upload/picture/pic/76650/3ba0e801-9bed-371c-a891-755160f1964b.jpg[/img]
[img]http://francis-xjl.iteye.com/upload/picture/pic/76652/d35d2dd4-c719-333b-b5f6-43decd40fb88.jpg[/img]
很显然,有四个new StringBuilder操作。基本可以得出结论:需要字符串连接的时候,如果没有可用的对应的StringBuilder就会去新建。因此字符串操作还是推荐自己手动去new StringBuilder,不能依赖编译器的优化。
当然会有很多其它情况,比如我在第三行代码后面加一个c+=a;a+=b;会产生什么样的情况呢?实践乃检验真理的唯一方法,自己去检测吧~~ :lol: