看題目就知道本文要說啥了~先上代碼!!java
public class StringAndStringBuilderTest { @Test public void testString() { String str = ""; for(int i = 0; i < 100; i++) { str += String.valueOf(i); } } @Test public void testStringBuilder() { StringBuilder sb = new StringBuilder(""); for(int i = 0; i < 100; i++) { sb.append(String.valueOf(i)); } } @Test public void testString() { String str = "a" + "b" + "c"; } }
上述代碼很明顯,分別測試:String鏈接產生多少對象?SringBuilder鏈接產生多少對象?在一條表達式中鏈接字符串產生多少對象?緩存
下面在給出該類的字節碼文件。。。app
public class StringAndStringBuilder { public StringAndStringBuilder(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return public void testString(); Code: 0: ldc #2 // String 2: astore_1 3: iconst_0 4: istore_2 5: iload_2 6: bipush 100 8: if_icmpge 39 11: new #3 // class java/lang/StringBuilder 14: dup 15: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V 18: aload_1 19: invokevirtual #5 // Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder; 22: iload_2 23: invokestatic #6 // Method java/lang/String.valueOf: (I)Ljava/lang/String; //產生一個String對象,並追加到StringBuilder後面 26: invokevirtual #5 // Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder; 29: invokevirtual #7 // Method java/lang/StringBuilder.toString: ()Ljava/lang/String; 32: astore_1 33: iinc 2, 1 36: goto 5 //作了個for循環,返回第5行 39: return public void testStringBuilder(); Code: 0: new #3 // class java/lang/StringBuilder 3: dup 4: ldc #2 // String 6: invokespecial #8 // Method java/lang/StringBuilder."<init>": (Ljava/lang/String;)V 9: astore_1 10: bipush 100 12: istore_2 13: iload_2 14: sipush 200 17: if_icmpge 35 20: aload_1 21: iload_2 22: invokestatic #6 // Method java/lang/String.valueOf: (I)Ljava/lang/String; //append方法裏,再次產生一個String對象 25: invokevirtual #5 // Method java/lang/StringBuilder.append: (Ljava/lang/String;)Ljava/lang/StringBuilder; 28: pop 29: iinc 2, 1 32: goto 13 //同理,此處爲循環,返回第13行 35: return public void testString02(); Code: 0: ldc #9 // String abc //這是個問題~~ 2: astore_1 3: return }
先看testString方法的字節碼:jvm
從iload_2開始,到goto,是個完整的循環體。請看第一份Java代碼測試
字節碼的第11--32行,編譯器自動將String鏈接轉化爲StringBuilder,並推入其緩存池。並將原String引用指向該StringBuilder的toString方法返回的String對象。ui
在第29行可見,最後調用toString並返回對象;第32行可見,依然從棧中彈出原來Srting引用str。code
因此,直接用String鏈接字符串的話,每用一次String的原引用,則會生成一個StringBuilder對象。對象
綜上所述,當緩存池非空時或原String非null,至少產生兩個對象,一個String,一個StringBuilder。當追加在StringBuilder後面的String並不存在與常量池,則最多產生2N+1個對象.ip
在看testStringBuilder方法的字節碼:ci
第13--32行,依然是個完整的循環體,請看第一份Java代碼
見字節碼,明顯與testString方法大不同。清晰不少。
循環體內,並沒有StringBuilder對象的產生,只有String.valueOf()方法生成出來的,要追加到StringBuilder的String對象。
顯然每次循環,少了StringBuilder對象的生成。
綜上所述,當緩存池非空時,至少產生兩個對象;當不斷得往緩存池裏追加字符串時,且新字符串並不存在於常量池,則最多產生N+1個對象。
testSting()產生2N+1個對象,testStringBuilder()產生N+1個對象,這就是StringBuilder鏈接字符串比String高效的緣故。
StringBuffer同理。
再看最後一個方法testString02()。。。
String str = "a" + "b" + "c" ;
真的只產生一個對象麼?字節碼只是表示出,從字符串常量池中彈出引用,並沒有說明JVM解析CONSTANT_String時,產生多少個String對象。
因此,求大俠解答最後提出的問題。jvm是如何解析CONSTANT_String滴???