2014-05-22 48 views
3

我不太瞭解String的實習方法。當我們使用String的實習方法時創建了多少個對象

String s1="java"; // should create one object in String Constant pool 

String ss="java"; // no object is created (java is already in String pool)..it refers to object in String constant pool 


String s2= new String("Android").intern(); // should create 2 objects one in heap and  second in String constant pool 

String s3= new String("java").intern()// i guess only one object is created on heap and s3 will point to object in String constant pool (as 'java' already exist).so the object in heap is lost because there is no reference 

請讓我知道我的理解是否正確?

+0

我認爲這是正確理解那個'String pool'的想法。 – RMachnik

+0

所以我所有的假設都是正確的? – sar

+0

*認爲使用'new String'的感覺* – Rogue

回答

5

你的前兩行是幾乎正確。從技術上講,這兩行代碼不會自行創建任何對象 - 字符串文字實際上在編譯時間處理並放置在字節代碼文件中的常量池中,這意味着實際的String對象是在在你寫的任何代碼運行之前,類首先被加載。因此,如果你要反編譯代碼的前兩行,你會得到這樣的:

0: aload_0  
1: invokespecial #1     // Method java/lang/Object."<init>":()V 
4: aload_0  
5: ldc   #2     // String java 
7: putfield  #3     // Field s1:Ljava/lang/String; 
10: aload_0  
11: ldc   #2     // String java 
13: putfield  #4     // Field ss:Ljava/lang/String; 
16: return 

正如你所看到的,是由兩種線創建任何String對象。字節碼只是將常數池中已有的String值(ldc表示load constant)賦值給那些變量

接下來的兩行有點不同。它可能更容易弄清楚是怎麼回事,如果你拆分鏈式調用到他們的組成部分:

String s2 = new String("Android"); 
s2 = s2.intern(); 
String s3 = new String("java"); 
s3 = s3.intern(); 

這被編譯成字節碼的:

0: new   #2     // class java/lang/String 
    3: dup   
    4: ldc   #3     // String Android 
    6: invokespecial #4     // Method java/lang/String."<init>":(Ljava/lang/String;)V 
    9: astore_1  
    10: aload_1  
    11: invokevirtual #5     // Method java/lang/String.intern:()Ljava/lang/String; 
    14: astore_1  
    15: new   #2     // class java/lang/String 
    18: dup   
    19: ldc   #6     // String java 
    21: invokespecial #4     // Method java/lang/String."<init>":(Ljava/lang/String;)V 
    24: astore_2  
    25: aload_2  
    26: invokevirtual #5     // Method java/lang/String.intern:()Ljava/lang/String; 
    29: astore_2  
    30: return   

所以你可以看到,new關鍵字觸發建造一個新的String對象。然後字符串"Android"從常量池加載並用於創建字符串。然後將其存儲到一個變量中。緊接着,該變量被取消引用,調用intern(),並將結果存儲回變量。此代碼與您的代碼之間的唯一區別是String構建和實習之間的額外存儲/加載。

所以對於每一個s2s3,只創建一個String對象 - 因此,你只看到兩個方法與<init>總。所有intern()所做的檢查是否該字符串已存在於字符串池中,如果存在,則返回該一個引用。

+0

從技術上講,這些對象是在鏈接/類加載時創建的,而不是編譯時。 – chrylis

+0

@chrylis當然,我想你可以這樣說......我更多地認爲在編譯時將所有創建對象的信息放入字節碼的常量池中,但是說出更合理的說法實際的對象是在運行期間的某個時候創建​​的...我會糾正我的答案。 – awksp

0

此行含有字符串文字不創建字符串對象

String s1="java"; 

或其它線路。它們是由JVM在加載包含字符串文本的類並放入字符串池期間創建的。

至於中的String.intern()它不會創建一個新的String,它只是檢查一個字符串是否已經在池中,如果它不存在將其添加到池

相關問題