2015-02-24 24 views
0

另一個考試的問題,這讓我感到困惑:String對象計數SCJP

public String makinStrings() { 
String s = 「Fred」; 
s = s + 「47」; 
s = s.substring(2, 5); 
s = s.toUpperCase(); 
return s.toString(); 
} 

的問題是: 「?有多少String對象時,調用此方法將創建」

正確的答案應該是3,但是我統計了:
弗雷德
Fred47
ED4
ED4

是3真的是正確的答案?如果是這樣 - 爲什麼?

回答

1

字符串常量在類被實例化的時刻被實例化。因此,字符串「Fred」和「47」在方法調用之前實例化,而不是在方法調用期間實例化。

這篇文章解釋它:The String Constant Pool

但我會完善多一點:Java虛擬機規範規定的常量「弗雷德」和「47」被放置在字符串常量池項。 (java SE specs, loading and linking)。

發生這種情況當班級被加載

另一個需要注意的問題是:問題是有多少對象實例化了

所以,

的String =「佛瑞德」:不實例化新的字符串對象,僅使用從內化「佛瑞德」恆定的參考。

s = s +「47」:'+'運算符意味着級聯操作;該連接的結果是一個新的String對象。所以,1個字符串實例化。在「47」中裝入類...

S = s.substring(2,5):方法定義指定一個新的字符串對象必須返回(String.substring javadoc),所以,2個字符串實例化。

即使實現(這種情況,例如the openJDK java.lang.String implementation)可以使用某種類型的構造,以僅參考字符陣列具有字符串內部值,則結果的一部分是一個新的字符串,即使一種「懶惰」的。

s = s.toUpperCase():在這裏相同,toUpperCase方法必須返回一個新的String。所以,3個字符串被實例化了。

最後,s.toString()以String形式返回對象的表示形式。由於字符串已經是一個字符串,s.toString()只返回完全相同的字符串對象...

+0

從Java語言規範[常量池自Java 7以來已移至Java堆](http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html#jdk7changes),以及之前該池在熱點JVM上位於'permgen space'中。 – 2015-02-24 12:26:49

+1

這並不排除字符串常量在方法調用過程中沒有實例化的事實,但是當類被實例化時,是不是? – 2015-02-25 23:59:19

+0

Nopes它不排除,但評論是在您的緩存內存概念提到的答案的前一個版本...... – 2015-02-26 09:27:46

0

3個對象:
弗雷德
Fred47
ED4

s = s + 「47」; 

47不會在字符串池中創建

s = s.substring(2, 5); 

不應該創建一個單獨的字符串,但將遵循flyweight模式和內部指向相同的字符串。

+0

爲什麼47不會在字符串池中創建,如果沒有,那麼它將在哪裏創建?和's.substring(2,5)'一定會在堆內存中創建新的字符串'對象' – 2015-02-26 09:28:04