字符串是 Java 程序中最常用的數據結構之一。在 Java 中 String 類已經重載了"+",字符串可以直接使用"+"進行連接,也可以用StringBuilder/StringBuffer(StringBuilder是J2SE5 及以上版本提供,以前的版本使用 StringBuffer 類)。哪種方式更好呢?如下:
public class TestString {
public static void main(String[] args) {
String str1 = "str1";
String str2 = "str2" + str1 + "OK" + 1;
System.out.println(str2);
}
}
``
編譯`javac TestString.java`,反編譯字節碼`javap -c TestString.class`:
```Compiled from "TestString.java"
public class TestString {
public com.swsc.solarverse.TestString();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String str1
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 // String str2
16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: iconst_1
20: invokevirtual #7 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
23: invokevirtual #8 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
26: astore_2
27: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
30: aload_2
31: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
34: return
}
可以看出,字符串對象通過“+”的字符串拼接方式,實際上是通過 StringBuilder 調用 append() 方法實現的,拼接完成之後調用 toString() 得到一個 String 對象 。但是,在循環內使用“+”進行字符串的拼接的話,會在循環體內循環創建StringBuilder 對象,如果直接使用StringBuilder拼接則不會。如:
public class TestString {
public static void main(String[] args) {
String str = "";
for(int i = 0; i < 3; i++){
str = str + i;
}
}
}
編譯javac TestString.java
,反編譯字節碼javap -c TestString.class
:
Compiled from "TestString.java"
public class TestString {
public com.swsc.solarverse.TestString();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: iconst_3
7: if_icmpge 35
10: new #3 // class java/lang/StringBuilder
13: dup
14: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
17: aload_1
18: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
21: iload_2
22: invokevirtual #6 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
25: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
28: astore_1
29: iinc 2, 1
32: goto 5
35: return
}
注意:使用 “+” 進行字符串拼接會產生大量的臨時對象的問題在 JDK9 中得到了解決。在 JDK9 當中,字符串相加 “+” 改爲了用動態方法makeConcatWithConstants() 來實現,而不是大量的 StringBuilder 了。這個改進是 JDK9 的 JEP 280open in new window 提出的,這也意味着 JDK 9 之後,可以放心使用“+” 進行字符串拼接了。Java9後String 的底層實現由 char[] 改成了 byte[]。
Compiled from "TestString.java"
public class TestString {
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String
2: astore_1
3: iconst_0
4: istore_2
5: iload_2
6: iconst_3
7: if_icmpge 24
10: aload_1
11: iload_2
12: invokedynamic #3, 0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;I)Ljava/lang/String;
17: astore_1
18: iinc 2, 1
21: goto 5
24: return
}