關于String為值型別還是參考型別的討論一直沒有平息,最近一直在研究性能方面的問題,今天再次將此問題進行一次明確,希望能給大家帶來點幫助,如果有錯誤請指出,
來看下面例子:
//值型別
int a = 1;
int b = a;
a = 2;
Console.WriteLine("a is {0},b is {1}", a, b);
//字串
String str1 = "ab";
String str2 = str1;
str1 = "abc";
Console.WriteLine("str1 is {0},str2 is {1}", str1, str2);
Console.Read();
根據上面的例子:你覺得輸出結果應該是什么?
輸出結果:
//a is 2,b is 1
//str1 is abc,str2 is ab
str2依然是ab,并沒有隨str1的改變而改變,
如果String是參考型別,按理Str1和Str指標都指向同一記憶體地址,如果Str的內容發生改變,Str1應該也會相應變化,
此例子,看著String更像是值型別,但是MSDN卻說String是參考型別,
參考型別包括:
String
所有陣列(即使其元素是值型別)
型別別(如Form)
委托
查看具體參考是否相同,如果Net能夠查看記憶體地址就容易了,但不允許,只能通過間接方法來實作,看下面:
static void TestRefAddress() { String str1 = "abc"; String str2 = "abc"; int a = 1; int b = 1; StringBuilder strb1 = new StringBuilder("abc"); StringBuilder strb2 = new StringBuilder("abc"); Console.WriteLine("Reference equal for string: " + Object.ReferenceEquals(str1, str2)); //結果true Console.WriteLine("Reference equal for int: " + Object.ReferenceEquals(a, b)); //結果false Console.WriteLine("Reference equal for StringBuilder: " + Object.ReferenceEquals(strb1, strb2)); //結果false Console.WriteLine("Value equal for string: " + str1.Equals(str2)); //結果true,類似于值型別 Console.Read(); }
結果為何出現如此情況,分析如下:
Console.WriteLine("Reference equal for string: " + Object.ReferenceEquals(str1, str2)); //結果true,不同物件,但參考地址相同
Console.WriteLine("Reference equal for int: " + Object.ReferenceEquals(a, b)); //結果false,值型別裝箱操作造成
Console.WriteLine("Reference equal for StringBuilder: " + Object.ReferenceEquals(strb1, strb2)); //結果false,不同物件,參考地址不同
Console.WriteLine("Value equal for string: " + str1.Equals(str2)); //結果true,類似于值型別
由第一條結果,可以判定不同的String的,相同的值,其參考地址相同,再由第四條結果,str1.Equals(str2),兩者結合,可得出結論,兩個String,如果賦值為同一個值,在記憶體中只有一個字串存在,兩個參考的地址相同,由此引出String的不變性,
String的不變性:
String最為顯著的一個特點就是它具有恒定不變性,我們一旦創建了一個String,在managed heap 上為他分配了一塊連續的記憶體空間,我們將不能以任何方式對這個String進行修改使之變長、變短、改變格式,所有對這個String進行各項操作(比如呼叫ToUpper獲得大寫格式的String)而回傳的String,實際上另一個重新創建的String,其本身并不會產生任何變化,
String 物件稱為不可變的(只讀),因為一旦創建了該物件,就不能修改該物件的值,有的時候看來似乎修改了,實際是String經過了特殊處理,每次改變值時都會建立一個新的String物件,變數會指向這個新的物件,而原來的還是指向原來的物件,所以不會改變,這也是String效率低下的原因,
String的不變,并非說String不能改變,而是其值不能改變,
在例子中str1="ab",這時在記憶體中就將“ab”存下來,如果再創建字串物件,其值也等于“ab”,str2="ab",則并非再重新分配記憶體空間,而是將之前保存的“ab”的地址賦給str2的參考,這就能印證例子2中的結果,而當str1="abc"其值發生改變時,這時檢查記憶體,發現不存在此字串,則重新分配記憶體空間,存盤“abc”,并將其地址賦給str1,而str2依然指向“ab”的地址,可以印證例子1中的結果,
結論:
String是參考型別,只是編譯器對其做了特殊處理,
轉載來源:https://www.cnblogs.com/littlewrong/p/9927154.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/108748.html
標籤:C#
