2011-10-04 82 views
0

我正在學習SCJP考試,我有一組樣本問題,我正在努力。字符串對象和堆

一個問題的答案我不確定,希望這裏有人能夠幫我把這個問題放在牀上。

這裏是問題,

考慮:

11. public String makinStrings() { 
12. String s = "Fred"; 
13. s = s + "47"; 
14. s = s.substring(2, 5); 
15. s = s.toUpperCase(); 
16. return s.toString(); 
17. } 

多少字符串調用此方法時對象將被創造出來的?

A. 1 
B. 2 
C. 3 
D. 4 
E. 5 
F. 6 

非常感謝您提供任何幫助。 我非常欣賞它。

+1

可能重複[多少String對象將被創建(http://stackoverflow.com/questions/7370593/how-many-字符串對象將被創建) –

+1

鏈接的問題甚至包含完全相同的示例。 –

+0

確實,這是一個確切的重複 – Guillaume

回答

7

讓我們逐行進行。

一個簡單的起點線,沒有在這裏創建的字符串。

線12

我們要指定字符串"Fred"s。雖然看起來像是在這裏創建了一個字符串,但該字符串將存在於常量池中。 JVMS部分2.17.6 Creation of New Class Instances保證在加載周邊類時創建最近的字符串文字的對象,在調用方法之前定義該對象的定義爲。所以在這一行上不會創建新的字符串對象。

線13

文本字符串"47"被參考,這再次將已經靜態創建的(如上述)。但也有調用+運算符,其中創建一個新的字符串以保存連接的結果。這是創建的第一個字符串。

線的substring方法確實創建一個新的String。它與父級共享底層字符數組 - 因此幾乎不佔用額外的內存 - 但由於字符串是不可變的,每個不同的字符串表示都需要一個不同的對象。 (這可能是一個陷阱 - 我的第一個直覺反應是「啊,由子字符串創建的字符串是特殊的」,但當然它仍然需要創建一個新對象)。

線15

如上 - 大寫表示是不同的,所以一個新的字符串必須創建保存結果。

線16

Strings倍率的toString()方法簡單地return this - 因此沒有額外的字符串被創建。

的字符串中引用的門上

我數這就是這種方法(期間創建兩個這些對象共享相同的底層字符數組三個String對象,並有兩個預先存在的對象得分文字)。

+0

這個答案重申了這個[鏈接]的答案(http://stackoverflow.com/questions/7370593/how-many-string-objects-will-be-created/7370800#7370800)所以謝謝你澄清。 – fluffy88

0

我會說3:在線路12,13和15

爲什麼線14(子)不創建新的對象是因爲內部字符串的方式工作的原因的人。由於必須對子字符串進行優化(包括編譯器在內的所有東西都依賴於子字符串),所以String類有兩個指向字符串開始和結尾的指針。做一個子字符串只會移動這個指針,並不會將該對象「複製」到一個新的。

+0

我同意。儘管'String.toUpperCase()'很棘手,但只有在需要修改任何字符時纔會創建新的String對象。 –

+0

從閱讀此回覆[鏈接](http://stackoverflow.com/questions/7370593/how-many-string-objects-will-be-created/7370800#7370800)3的確是答案,但在第13行, 謝謝你的迴應:) – fluffy88

+0

@JarekPrzygódzki這也是我的想法 - substring不會改變字符,但toUpperCase會(在這種情況下無論如何) – Guillaume

2

實際上,將整個方法變成一個常量是可能的。這是可能的,但編譯器不允許這樣做。因此,使用常量池中的2創建了3個字符串。

  • Fred47
  • ED4(注意:使用相同背襯的char []作爲Fred47雖然)
  • ED4

2和3是相當容易的,因爲編譯器是不允許優化掉此方法調用但字符串已更改。 Sting.toString()只返回this,所以沒有新的字符串。但是,讓我們對使用反彙編字節碼13號線一看(javap -c在這裏你的朋友):

public java.lang.String makinStrings(); 
    Code: 
    0: ldC#16; //String Fred 
    2: astore_1 
    3: new #18; //class java/lang/StringBuilder 
    6: dup 
    7: aload_1 
    8: invokestatic #20; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String; 
    11: invokespecial #26; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 
    14: ldC#29; //String 47 
    16: invokevirtual #31; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    19: invokevirtual #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
     // SNIP 
} 

正如你看到的,「弗雷德」和「47」是從常量池(ldc)加載到填充最終將成爲String(StringBuilder.toString())的StringBuilder。

這樣就可以爲每個方法調用創建2個常量字符串和3個新創建的字符串。

+0

現在,這是一個很好的答案,包括反彙編的代碼,榮譽。 – Guillaume

0

它會創建串的5個對象

字符串是不可變的類,以便爲每一個新字符串,它會創建一個對象。

例如

  1. 公共字符串makinStrings(){
    1. 的String = 「佛瑞德」; (此線創建1 --- Fred字符串)
    2. s = s +「47」; (此行創建2-47字符串+ 3- Fred47)
    3. s = s.substring(2,5); (這行創建4-ed4)
    4. s = s.toUpperCase();(這行創建5-ED4)
    5. return s。的toString();

所以根據我來說,這將創造5對象