先来看看两个简单字符串相连的情况,上代码
3 String str = "a" + "a";
4 return str;
5 }
6
7 public static String testJoinStringBuffer() {
8 StringBuffer sb = new StringBuffer();
9 sb.append("a");
10 sb.append("a");
11 return sb.toString();
12 }
13 }
编译完成后,我们CMD里
javap -verbose Test >> Test.txt 将字节码反编译成JAVA中间代码。直接看主体部分。
--------------------------------------------
public static java.lang.String testJoinString();
Code:
Stack=1, Locals=1, Args_size=0
0: ldc #16; //String aa
2: astore_0
3: aload_0
4: areturn
public static java.lang.String testJoinStringBuffer();
Code:
Stack=2, Locals=1, Args_size=0
0: new #21; //class java/lang/StringBuffer
3: dup
4: invokespecial #23; //Method java/lang/StringBuffer."<init>":()V
7: astore_0
8: aload_0
9: ldc #24; //String a
11: invokevirtual #26; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
14: pop
15: aload_0
16: ldc #24; //String a
18: invokevirtual #26; //Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
21: pop
22: aload_0
23: invokevirtual #30; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
26: areturn
--------------------------------------------
看红色的部分
String连接的情况下:
0: ldc #16; //String aa ,
可以看到在编译的时候,已经直接进行了表达式合并优化,所以直接就加载了 aa
StringBuffer的情况下:
9: ldc #24; //String a
16: ldc #24; //String a
加载了二次
从上面我们看到,在少量的简单字符串与字符串的连接,不涉及变量的情况下。String的+号连接在编译时已经进行了优化,所以效率是要比StringBuffer高的。
下面我们再来看看 简单的字符串和变量相连的情况,上代码
3 String str1 = "a" ;
4 String str2 = "a" + str1 ;
5 return str2 ;
6 }
7 public static String testJoinStringBuffer(){
8 StringBuffer sb = new StringBuffer();
9 sb.append("a") ;
10 sb.append("a") ;
11 return sb.toString() ;
12 }
13 }
同样 CMD里 javap -verbose Test1 >> Test1.txt
看主体部分
--------------------------------------------
public static java.lang.String testJoinString();
Code:
Stack=3, Locals=2, Args_size=0
0: ldc #16; //String a
2: astore_0
3: new #18; //class java/lang/StringBuilder
6: dup
7: ldc #16; //String a
9: invokespecial #20; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
12: aload_0
13: invokevirtual #23; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
16: invokevirtual #27; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
19: astore_1
20: aload_1
21: areturn
--------------------------------------------
StringBuffer部分代码没有变更为节省篇幅,这里就不现列出来,可以拉上去看一看
再看红色部分
String 的+号连接
0: ldc #16; //String a
7: ldc #16; //String a
13: invokevirtual #23;
//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
可以看出其实String的+号连接,仍然是调用了StringBuffer.append方法进行的。
所以在少量简单字符串与变量的连接时,两者效率是基本上一样的
下面我们来看最后一种情况。 大量的字符串与变量的连接 上代码
3 String str = "a" ;
4 for( int i=0;i<100;i++){
5 str += "a" + i ;
6 }
7 return str ;
8 }
9
10 public static String testJoinStringBuffer(){
11 StringBuffer sb = new StringBuffer();
12 for( int i =0;i<100;i++){
13 sb.append("a") ;
14 sb.append(i) ;
15 }
16 return sb.toString() ;
17 }
18 }
Javap -verbose Test2 >> Test2.txt
主体部分
--------------------------------------------
public static java.lang.String testJoinString();
Code:
Stack=3, Locals=2, Args_size=0
0: ldc #16; //String a
2: astore_0
3: iconst_0
4: istore_1
5: goto 35
8: new #18; //class java/lang/StringBuilder
11: dup
12: aload_0
13: invokestatic #20;
//Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
16: invokespecial #26; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
19: ldc #16; //String a
21: invokevirtual #29;
//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: iload_1
25: invokevirtual #33;
//Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
28: invokevirtual #36; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore_0
32: iinc 1, 1
35: iload_1
36: bipush 100
38: if_icmplt 8
41: aload_0
42: areturn
public static java.lang.String testJoinStringBuffer();
Code:
Stack=2, Locals=2, Args_size=0
0: new #45; //class java/lang/StringBuffer
3: dup
4: invokespecial #47; //Method java/lang/StringBuffer."<init>":()V
7: astore_0
8: iconst_0
9: istore_1
10: goto 29
13: aload_0
14: ldc #16; //String a
16: invokevirtual #48;
//Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
19: pop
20: aload_0
21: iload_1
22: invokevirtual #51; //Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;
25: pop
26: iinc 1, 1
29: iload_1
30: bipush 100
32: if_icmplt 13
35: aload_0
36: invokevirtual #54; //Method java/lang/StringBuffer.toString:()Ljava/lang/String;
39: areturn
------------------------------------------
看上面的红色部分 (主体部分)
testJoinString
5: goto 35
8: new #18; //class java/lang/StringBuilder
19: ldc #16; //String a
21: invokevirtual #29;
//Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
25: invokevirtual #33;
//Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
28: invokevirtual #36; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
36: bipush 100
38: if_icmplt 8
testJoinStringBuffer
0: new #45; //class java/lang/StringBuffer
13: aload_0
14: ldc #16; //String a
16: invokevirtual #48;
// Method java/lang/StringBuffer.append:(Ljava/lang/String;)Ljava/lang/StringBuffer;
22: invokevirtual #51; //Method java/lang/StringBuffer.append:(I)Ljava/lang/StringBuffer;
30: bipush 100
32: if_icmplt 13
从上面可以看出来。String的+号连接,在循环体内部(8~28),每次都要 new 一个StringBuffer 出来,而 StringBuffer.append 方法,只是在循环体外,new 一个StringBuffer出来 。
这样如果循环很大的话,String 的+号连接是相当耗费资源和时间的。