關於String與StringBuilder的提問與總結

看題目就知道本文要說啥了~先上代碼!!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滴???

相關文章
相關標籤/搜索