2016-11-08 89 views
1
String str = "test"; 

str = str + "test2"; 
str = str + "test3"; 
str = str + "test4"; 
str = str + "test5"; 

上面的代碼將創建多少個對象,以及有多少對象可用於垃圾回收?將創建多少個對象以及將有多少對象可用於垃圾回收?

有人能解釋一下嗎?

+2

請參閱http://stackoverflow.com/questions/10443492/how-many-objects-are-created,但該問題已過了幾年,可能已過時。 – ajb

+0

查看http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.18.1,似乎沒有明確的答案 - 不同的實現可能會有所不同的東西。 – ajb

回答

0

關於字符串操作,JavaC是非常奇怪的。例如,當你做「String + = otherString」時爲什麼不使用String.concat?

取而代之的是,Java爲每行結束的每行創建一個StringBuilder(或StringBuffer,取決於Java版本);你已經連接了字符串。

我把你的代碼的測試程序(TCTestWin)和命令行調用:

javap -c TCTestWin.class 

這些結果如下:

0: ldc   #15     // String test 
    2: astore_1 
    3: new   #17     // class java/lang/StringBuilder 
    6: dup 
    7: aload_1 
    8: invokestatic #19     // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 
    11: invokespecial #25     // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 
    14: ldc   #28     // String test2 
    16: invokevirtual #30     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    19: invokevirtual #34     // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    22: astore_1 
    23: new   #17     // class java/lang/StringBuilder 
    26: dup 
    27: aload_1 
    28: invokestatic #19     // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 
    31: invokespecial #25     // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 
    34: ldc   #38     // String test3 
    36: invokevirtual #30     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    39: invokevirtual #34     // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    42: astore_1 
    43: new   #17     // class java/lang/StringBuilder 
    46: dup 
    47: aload_1 
    48: invokestatic #19     // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 
    51: invokespecial #25     // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 
    54: ldc   #40     // String test4 
    56: invokevirtual #30     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    59: invokevirtual #34     // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    62: astore_1 
    63: new   #17     // class java/lang/StringBuilder 
    66: dup 
    67: aload_1 
    68: invokestatic #19     // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 
    71: invokespecial #25     // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 
    74: ldc   #42     // String test5 
    76: invokevirtual #30     // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    79: invokevirtual #34     // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    82: astore_1 
    83: return 

正如你所看到的,對於每一行,javac的創建一個StringBuilder,追加字符串,並繼續。

這樣的代碼,特別是在循環內部使用時,會衝高垃圾收集器。

有三種更好的方法來做到這一點:

  1. 使用CONCAT代替:

    String str = "test"; 
    str = str.concat("test2"); 
    str = str.concat("test3"); 
    str = str.concat("test4"); 
    str = str.concat("test5"); 
    
  2. 使用串聯的單行線,這將創建一個單一的StringBuilder。請記住每個;將創建另一個StringBuilder。請注意,在下面的常量字符串串聯中,Java編譯器將創建一個字符串。但是,如果添加一個或多個字符串變量,則將創建StringBuilder。

    String str = "test" + "test2" + "test3" + "test4" + "test5"; 
    
  3. 創建一個StringBuilder自己,做串聯,並REUSE StringBuilder的。這有最好的表現,特別是當做在循環

    StringBuilder sb = new StringBuilder(512); 
    for (int i = 0; i < 10000; i++) 
    { 
        sb.setLength(0); 
        sb.append("test"); 
        sb.append("test2"); 
        sb.append("test3"); 
        sb.append("test4"); 
        sb.append("test5"); 
        sb.append(i); 
        String s = sb.toString(); 
    } 
    

因此,從上面的代碼中,4個不同的StringBuilders將被創建。在最終的String之後,所有的StringBuilders都將被收集。

+1

如果您使用編號或項目符號,則以下代碼需要雙縮進。 – EJP

+0

它們不使用多個'String.concat()'調用,因爲單個'StringBuilder'效率更高。編譯器選擇比程序員能想到的更好的目標代碼沒有什麼「非常奇怪的」。這就是他們的目的。注意你沒有真正回答這個問題。 – EJP

+0

完全同意...如果...創建了一個StringBuilder。但是,發佈的代碼不會創建單個StringBuilder,而是創建4個! –

0

多少對象將被創建

在運行時,如圖4所示,即str四個計算值,但不包括其中來自於常量池的初始值。

以及有多少對象可用於垃圾回收?

在該代碼的末尾但在str超出範圍之前,三個即str的三個中間值。

請注意,我計數Strings。每個String將有一個關聯char[]這是另一個對象。

但是,如果周圍的代碼使得JVM可以確定str不能在這些代碼行之間改變,則它可能分別低至1和0。

+0

我想'String str =「test」;'也會在String常量池中創建一個對象,它位於JVM的堆內存中。所以沒有。的對象將是5. –

+0

@RohitGaikwad但在運行時不執行此代碼。它發生在課程加載時間。 – EJP