2016-11-21 46 views
0

執行String S1 = "hello";後JVM將在SCP創建字符串對象,並該對象將持有字符數組中value場像使用新字符串(「hello」)在簡單的「hello」中完全無用,當它間接指向「hello」時?

s1.value = {'h', 'e', 'l', 'l', 'o'} 

當我們說

String s2 = new String("hello"); 

並根據源代碼String類在構造函數執行後s2.value也將變爲"hello".value,它將類似於s1.value

public String(String original) { 
    this.value = original.value; 
    this.hash = original.hash; 
} 

所以每次我們創建一個使用new JVM String對象將創建在堆

  1. 一個對象,並
  2. 一個字符串字面對象SCP的時間,如果它已經不存在

堆中的對象在內部指向SCP中的文字對象。

而每一次,我們作出s2或以其他任何字符串的變化(不要緊它是從字面上或使用new創建)字面一個新字符串將會在堆中,這是新更改s2將創建點。使用String s2 = new String("hello")不會創建"hello"堆中的對象。 JVM正在SCP中創建"hello",除非它不存在,s2指向它。

我的問題是,new String("hello")或簡單的"hello"有什麼區別。當使用public String(String original)剛剛創建堆空字符串對象,並浪費內存爲什麼Java允許開發人員調用public String(String original),爲什麼它甚至在String類提供什麼好處它給

我的問題是什麼?

+0

新的字符串(「文本」)使字符的副本[] –

+0

@simas_ch:不,它不。它曾經這樣做,但三年前就改變了。 – Holger

+0

@Jens我已經更新了這個問題,這個問題與您提到的問題並不重複 –

回答

1

有一個有趣的說法在約書亞布洛赫的「有效的Java」,第2版,第4章,第15項:

的事實是不可變對象可以自由共享的一個後果是, 你永遠不會有製作防禦性拷貝(條目39)。事實上,你永遠不必 任何副本,因爲副本將永遠等於原件。 因此,您不需要也不應該提供clone方法或複製 構造函數(項目11)在不可變類上。這在Java平臺早期的 中並沒有得到很好的理解,所以String類確實有一個拷貝構造函數 ,但它應該很少使用(項目5)。

(第76頁在我的副本)
我認爲,約書亞布洛赫可以看作是一個權威的來源,尤其是詹姆斯·高斯林,Java的發明者之一,已被列爲說,「我當然希望我十年前寫過這本書......「(指的是2001年的第一版)。


所以String(String)構造的存在,可以被看作是一個設計錯誤,多爲無參數的構造函數String()。還請注意工廠方法String.valueOf(char[])/String.valueOf(char[],int,int)String.copyValueOf(char[])/String.copyValueOf(char[],int,int)的存在,其命名錶明存在根本不存在的根本差異。 String的不可變性質要求所有變體創建所提供陣列的防禦副本,以防止後續修改。因此,行爲是完全相同的(文檔明確告訴您),無論您使用的是valueOf還是copyValueOf


這就是說,有一些實際的用例,雖然不一定在初衷之內。其中一些在this question的答案中進行了描述。由於new操作保證產生新的實例,因此對於任何依賴於不同身份的後續操作可能是有用的,例如,在該實例上進行同步(不是這是一個好主意),或者試圖通過身份比較來識別該實例,以確保它不是來自外部源。例如,您可能想要區分屬性的默認值和已明確設置的值。但是,這樣做的用處有限,因爲即使字符串內容沒有更改,其他代碼也可能無法保持對象身份的正確性。或者它可能會記住你的特殊實例並在它遇到字符串時重用它。

爪哇7,更新6,String之前有一個offsetlength字段,允許廉價substring操作,指的是原始陣列內的範圍內,而不進行復制。這導致了這樣一種情況,一個(概念上)小的字符串可以持有對一個相當大的數組的引用,從而防止其垃圾收集。對於參考實現(由Sun/later Oracle提供),通過構造函數String(String)重新創建字符串,生成了帶有全新數組副本的String,只佔用盡可能多的內存。因此,這是在String(String)構造函數的使用情況納入實現特有的修復,以實現特有的問題...

當前的Java版本不維護這些offsetlength領域,這意味着一個潛在的更加昂貴的substring操作,但沒有複製行爲了。這是你在問題中引用的源代碼版本。舊版本可在this answer中找到。

+0

因此對於當前版本的Java 8,字符串的拷貝構造函數是完全無用的,甚至會降低性能你的Java應用程序 –

相關問題