也有人说,String在上述的问题中已经会自动引入StringBuilder来解决效率问题。
为此,我在《Java编程思想》中找到了答案。
第一个小例子:
package ;
public class TestString {
public static void main(String[] args)
{
String mango = "mango";
String someting = "abc" + mango + "def" + 47;
(someting);
}
}
执行编译,命令:
javac
用javap来反编译上述代码,看看都发生了什么故事:
javap -c TestString
结果如下:
Compiled from ""
public class extends {
public ();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public static void main([]);
Code:
0: ldc #2; //String mango
2: astore_1
3: new #3; //class java/lang/StringBuilder
6: dup
7: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
10: ldc #5; //String abc
12: invokevirtual #6; //Method java/lang/:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_1
16: invokevirtual #6; //Method java/lang/:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: ldc #7; //String def
21: invokevirtual #6; //Method java/lang/:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: bipush 47
26: invokevirtual #8; //Method java/lang/:(I)Ljava/lang/StringBuilder;
29: invokevirtual #9; //Method java/lang/:()Ljava/lang/String;
32: astore_2
33: getstatic #10; //Field java/lang/:Ljava/io/PrintStream;
36: aload_2
37: invokevirtual #11; //Method java/io/:(Ljava/lang/String;)V
40: return
}
从上述代码中看,编译器确实创建了一个StringBuilder对象。
但是,这并不能因此就说明可以随意的使用String对象。下面又举了个例子:
package ;
public class StringAndBuilder {
public String implicit(String[] fields)
{
String result="";
for(int i=0;i<;++i)
{
result+=fields[i];
}
return result;
}
public String explicit(String[] fields)
{
StringBuilder result=new StringBuilder();
for(int i=0;i<;++i)
{
(fields[i]);
}
return ();
}
}
反编译一下:
[linc@localhost TestString]$ javac
[linc@localhost TestString]$ javap -c StringAndBuilder
Compiled from ""
public class extends {
public ();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
public implicit([]);
Code:
0: ldc #2; //String
2: astore_2
3: iconst_0
4: istore_3
5: iload_3
6: aload_1
7: arraylength
8: if_icmpge 38
11: new #3; //class java/lang/StringBuilder
14: dup
15: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
18: aload_2
19: invokevirtual #5; //Method java/lang/:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: aload_1
23: iload_3
24: aaload
25: invokevirtual #5; //Method java/lang/:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #6; //Method java/lang/:()Ljava/lang/String;
31: astore_2
32: iinc 3, 1
35: goto 5
38: aload_2
39: areturn
public explicit([]);
Code:
0: new #3; //class java/lang/StringBuilder
3: dup
4: invokespecial #4; //Method java/lang/StringBuilder."<init>":()V
7: astore_2
8: iconst_0
9: istore_3
10: iload_3
11: aload_1
12: arraylength
13: if_icmpge 30
16: aload_2
17: aload_1
18: iload_3
19: aaload
20: invokevirtual #5; //Method java/lang/:(Ljava/lang/String;)Ljava/lang/StringBuilder;
23: pop
24: iinc 3, 1
27: goto 10
30: aload_2
31: invokevirtual #6; //Method java/lang/:()Ljava/lang/String;
34: areturn
}
注意到implicit方法,从第8行到第35行构成了一个循环体。StringBuilder是在循环体内构造的,也就是说,每经过一次循环,就会创建一个新的StrinBuilder对象。
再看explicit方法,循环部分的代码更简短、简单,而且只生成了一个StrinBuilder对象。
结论:
当为一个类编写toString()方法时,如果操作比较简单,就可以信赖编译器,它会为你合理的构造最终的字符串结果。如果使用了循环,那么最好自己创建一个StringBuilder对象。
如果拿不准该用那种方式,就用javap来分析你的程序吧!
另外,linc之前还翻译了一段小文章,是讲String、StringBuffer和StringBuilder之间的区别的:/lincyang/article/details/6333041