2016-03-29 73 views
3
string s1 = "abc"; 
string s2 = s1; 
s2 = "123"; 
Debug.Log(s1 + ":" + s2); 

結果是ABC:123字符串是引用類型,但爲什麼它的值類型的工作時,它的分配更新

那麼,爲什麼S1未更新爲123 S1和S2包含相同的參考並且如果一個變量更新它然後第二個會自動更新。

+0

字符串是不可變 –

+0

@取消幸運問題的標題是相同的,但問題內容是不同的。我已經檢查過 –

+0

字符串是不可變的(或者它們是引用或值類型)對於這個問題並不重要。這個問題是關於變量的,而不是關於它們的內容。 – Jcl

回答

3

這是對參考文獻使用的常見誤解。

s1是一個引用類型,但其內容是一個值。您可以認爲所有變量都是值類型,但編譯器處理它們的方式因值或引用類型而異。

string s1 = "abc"; 

S1等於其中「ABC」的地址被存儲,讓我們說0x0000AAAA

string s2 = s1; 

S2指向相同的地址S1因此,它的值是相同的S1。兩者都有價值0x000AAAA

s2 = "123"; 

字符串是不可變的,這意味着你不能修改字符串,任何時候你分配一個新值或修改,您要創建一個新的字符串在內存中的其他地方,而前一個準備好了GC ,如果需要的話(實際上不是這樣)。此時,s1的值仍然爲0x0000AAAA,而s2的值爲0X0000BBBB。

Debug.Log(s1 + ":" + s2); 

由於兩個點在不同的內容,他們打印不同的結果。

它只是一個引用類型,因爲變量中包含的值並不是要按原樣使用,而是要將指針發送到存儲實際對象的內存中的地址位置。

除非使用out/ref(C++中的&),則暗示將使用該變量的值(地址),最有可能作爲參數。

請注意,此行爲與任何對象相同,不僅是字符串。

Dog dogA = new Dog(); 
Dog dogB = dogA; 
dogA.name = "Wolfie"; // Affect both since we are dereferencing 
dogA = new Dog(); // dogA is new object, dogB is still Wolfie 

編輯:OP需要解釋關於ref/out。

當你想改變一個對象,你會覺得以下幾點:

void ChangeObject(GameObject objParam) 
{ 
    objParam = new GameObject("Eve"); 
} 

void Start(){ 
    GameObject obj = new GameObject("Adam"); 
    ChangeObject(obj); 
    Debug.Log(obj.name); // Adam...hold on should be Eve (??!!) 
} 

的ChangeObject得到一個GameObejct作爲參數,編譯器拷貝OBJ(00000AAAA)包含到objParam價值,它使一個副本它和現在都具有相同的價值。

在該方法中,objParam被賦予一個新的值,並且與方法外部的obj沒有更多的關聯。 objParam是該方法的局部,並在完成時被移除(遊戲對象仍然在場景中,但引用丟失)。

如果您希望在更改方法中的obj:

void ChangeObject(ref GameObject objParam) 
{ 
    objParam = new GameObject("Eve"); 
} 

void Start(){ 
    GameObject obj = new GameObject("Adam"); 
    ChangeObject(ref obj); 
    Debug.Log(obj.name); // Yeah it is Eve !!! 
} 

這一次,它不是傳遞obj的價值,但obj的地址。所以obj可能包含0x0000AAAA,但它自己的地址是0x0000AABB,那麼objParam的值現在是0x0000AABB,並且更改objParam意味着更改存儲在0x0000AABB處的值。

out和ref的工作方式是一樣的,只有out需要在方法內賦值,而ref可以離開方法而不影響給定的參數。

+0

你能否定義它更多'除非你使用/ ref(&在C++中),那麼它暗示着變量的值將被使用(地址),很可能是一個參數。 –

0

因爲變量不是對象。變量是引用對象

當你做s2 = "123",你重新分配參考變量s2(而不是它指出對象),爲不同的對象(與值123

是的,string是不可改變的類型string的對象(如其他人士),但實際上不是對這個問題的罪魁禍首。這發生在可變和不可變類型以及值和引用類型。關鍵的區別在於,您正在修改變量指向的引用(內存地址),因此您不會更改該內存地址的內容。

用值類型:

int i1 = 0; 
int i2 = i1; 
i2 = 2; 
Debug.Log(i1.ToString() + ":" + i2.ToString()); 

會記錄:0:2

並與參考類型:

public class MyClass { 
    private string _cont; 
    public MyClass(string cont) { _cont = cont; } 
    public override string ToString() { return _cont; } 
} 

MyClass c1 = new MyClass("abc"); 
MyClass c2 = c1; 
c2 = new MyClass("123"); 
Debug.Log(c1.ToString() + ":" + c2.ToString()); 

也將登錄abc:123

只有兩種方式在C#中更改內存地址的實際內容的變量指向:一是用unsafe指針(它們有自己的語法),另一個是將該變量作爲refout參數傳遞給方法(並且需要明確完成)。

1

字符串是不可變的。 當您分配string s1 = "abc"時,您正在將由字符串文字abc創建的新對象引用分配給s1的引用。
因此,當您指定s2 = "123";時,s2將引用由字符串文字"123"創建的新對象。
希望這有助於!

1

通過將一個字符串文字賦值給一個String變量,您實際上是實例化一個新的字符串對象並將其分配給現有的字符串對象。即

如果我們聲明並初始化s1如下;

string s1 = "abc"; 

實際上正在發生的事情是,我們正在創造一個新的字符串對象abc並分配給s1這是類似的:假設Foo是一類]。

Foo fooObj= new Foo(); 
fooObj= new Foo(); // this will be a new instant 

還有一點需要澄清; new Foo();將在內部創建一個對象,並分配給fooObj我們無法改變的new Foo();的價值,因爲它在內部創建,但我們可以處理fooObj

+0

很好的回答方式,但幾乎相同的事情已經由fafse說。謝謝 –

相關問題