2016-08-05 110 views
-6

我知道字符串inmutable,曾經創造了我們無法改變它,我讀過,如果我們創建一個新的字符串對象,我們分配一個值,然後我們另一個值分配到相同的字符串對象在內部實際上有一個是對象創建並賦值爲新值。比方說,我有:字符串如何在c#中工作?

string str = "dog";    
str = "cat"; 

如果我寫Console.WriteLine(str);返回cat。 所以內部有兩個對象?但他們有相同的名字?它是如何工作的?我對谷歌做了一些研究,但是我還沒有找到足夠令人信服的東西,所以我可以澄清我對此的看法。 我知道字符串是引用類型,所以我們在堆棧中有一個對象引用堆中的值,在這種情況下發生了什麼?(請參閱上面的代碼)。

我已經上傳圖片,道歉我,如果我錯疊的想法,這就是爲什麼我問這個問題堆。 圖片是否反映了第一行代碼(string str = "dog";)中發生的情況?然後在第二行代碼中會發生什麼?堆中的dog值發生了變化?然後創建一個新的對象引用它?那麼之前的對象會發生什麼?他們有相同的名字嗎? 我很抱歉有這麼多問題,但我認爲這對正確理解這一點非常重要,並且要知道幕後發生了什麼... enter image description here

回答

2

評論String Interning.Net String Intern tableCLR Intern Pool
基本上,公共語言運行時(CLR)維護一個[unique]字符串值的表,並且無論何時在代碼中操作字符串時,CLR都會檢查此實習生表,看看您嘗試創建的新值是否已經在那裏或沒有。如果是這樣,它只是重新分配您正在修改的變量以指向intern池中的該條目。如果不是,則將該值添加到池並返回新的引用。池中的舊值,不再由變量引用,會收集垃圾。

+0

我很難選擇一個答案,因爲你所有的答案都非常具有描述性,現在我已經澄清了這件事,謝謝! – AlexGH

1

是的,有兩個對象。不,他們沒有相同的名字。儘量不要將變量想象爲對象本身的「名稱」本身 - 它更像是對象在內存中的位置的臨時名稱。 (將變量視爲對象的「名稱」有點誤導的原因是,您可以有多個變量引用同一個對象;對象本身並不具有多個「名稱」,或者在那裏是幾個對象 - 這就是你碰巧存儲參考的方式)。

「字符串str」最初有這個字符串的引用「狗」。將「cat」分配給「str」後,該變量現在引用字符串「cat」。

兩個字符串仍然存在於內存(至少是暫時的),而是因爲你沒有給它(並因此不再是「知道」它的位置)提到「狗」字符串不再能訪問。你不會提前知道它們在內存中的存在時間,儘管垃圾收集器可以在任何時候從內存中刪除「dog」字符串,因爲不再有任何對它的引用。

你對堆棧的方式引用的對象在堆上的價值正確的 - 這是一個很好的區分。

2

你很近。您的照片準確地代表了第一行代碼中發生的情況。但是,與第二行代碼描述的內容有些不同。

對於行str = "cat";,將在堆中創建第二個字符串對象,並將str變量更改爲引用該新對象。您剩下的str指向堆上的"cat"和一個孤兒"dog"對象,但沒有對它的引用。

"dog"對象可能由垃圾回收,因爲有對它的引用清理。

4

當您將str指定爲「dog」時,它的確如上面在內存中描述的那樣執行:參考變量str現在「指向」您剛剛實例化的字符串的位置。

str => MEMORY LOCATION "1": "dog" 
     MEMORY LOCATION "2": 
     MEMORY LOCATION "3": 

str被重新分配到新的字符串,「貓」,它也是在內存中創建的,現在str進行調整,使其指向在新位置「貓」。

 MEMORY LOCATION "1": "dog" 
str => MEMORY LOCATION "2": "cat" 
     MEMORY LOCATION "3": 

「狗」會發生什麼?現在它實際上是無法訪問的,因爲我們不再提及它的位置(在內存中,堆,術語在這種情況下是可以互換的)。之後,當垃圾收集器檢查內存以進行清理時,它會意識到沒有任何引用「dog」的內容,它會標記內存是否被刪除並根據需要進行替換。