1. 程式人生 > >淺談C#中的值類型和引用類型

淺談C#中的值類型和引用類型

title log 創建 編譯 設計 編寫 通過 發布 構造

在C#中,值類型和引用類型是相當重要的兩個概念,必須在設計類型的時候就決定類型實例的行為。如果在編寫代碼時不能理解引用類型和值類型的區別,那麽將會給代碼帶來不必要的異常。很多人就是因為沒有弄清楚這兩個概念從而在編程過程中遇到了很多問題,在這裏博主淺談對值類型和引用類型的認識。

首先從概念上看,值類型直接存儲其值,而引用類型存儲對其值的引用。從而這兩種類型存儲在內存的不同地方。

其次從內存空間上看,值類型是在棧中操作,而引用類型則在堆中分配存儲單元。

棧在編譯的時候就分配好內存空間,在代碼中有棧的明確定義,而堆是程序運行中動態分配的內存空間,可以根據程序的運行情況動態地分配內存的大小。因此,值類型總是在內存中占用一個預定義的字節數。而引用類型的變量則在棧中分配一個內存空間,這個內存空間包含的是對另一個內存位置的引用,這個位置是托管堆中的一個地址,即存放此變量實際值的地方。

也就是說值類型相當於現金,要用就直接用,而引類型相當於存折,要用得先去銀行取。

但值類型在棧上分配內存,而引用類型在托管堆上分配內存,只是一種籠統的說法。下面對其進行詳細描述。

(1)對於值類型的實例,如果作為方法中的局部變量,則被創建在線程棧上;如果該實例作為類型的成員,則作為類型成員的一部分,連同其他類型字段存放在托管堆上。

每種值類型均有一個隱式的默認構造函數來初始化該類型的默認值。例如:

int i = new int(); 

等價於:

Int32 i = new Int32(); 

等價於:

int i = 0; 

等價於:

Int32 i = 0
;

使用new運算符時,將調用特定類型的默認構造函數並對變量賦以默認值。在上例中,默認構造函數將值0賦給了i。

說明:C#的所有值類型均隱式派生自System.ValueType,而System.ValueType直接派生於System.Object。即System.ValueType本身是一個類類型,而不是值類型。其關鍵在於ValueType重寫了Equals方法,從而對值類型按照實例的值來比較,而不是引用地址來比較。

(2)引用類型的實例創建在托管堆上。

下面以一段代碼來詳細講解一下值類型與引用類型的區別

 1    namespace Test 
 2    {  
3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //調用ReferenceAndValue類中的Demonstration方法 8 ReferenceAndValue.Demonstration(); 9 Console.ReadLine(); 10 } 11 } 12 public class stamp //定義一個類 13 { 14 public string Name { get; set; } //定義引用類型 15 public int Age { get; set; } //定義值類型 16 } 17 public static class ReferenceAndValue //定義一個靜態類 18 { 19 public static void Demonstration() //定義一個靜態方法 20 { 21 stamp Stamp_1 = new stamp { Name = "Premiere", Age = 25 }; //實例化 22 stamp Stamp_2 = new stamp { Name = "Again", Age = 47 }; //實例化 23 int age = Stamp_1.Age; //獲取值類型Age的值 24 Stamp_1.Age = 22; //修改值類型的值 25 stamp guru = Stamp_2; //獲取Stamp_2中的值 26 Stamp_2.Name = "Again Amend"; //修改引用的Name值 27 Console.WriteLine("Stamp_1‘s age:{0}", Stamp_1.Age); //顯示Stamp_1中的Age值 28 Console.WriteLine("age‘s value:{0}", age); //顯示age值 29 Console.WriteLine("Stamp_2‘s name:{0}", Stamp_2.Name); //顯示Stamp_2中的Name值 30 Console.WriteLine("guru‘s name:{0}", guru.Name); //顯示guru中的Name值 31 } 32 } 33 }

通過運行上面一段程序之後我們可以看出,當改變了Stamp_1.Age的值時,age並沒有跟著變,但在改變了anders.Name的值後,guru.Name卻跟著變了,這就是值類型和引用類型的區別。在聲明age值類型變量時,將 Stamp_1.Age的值賦給它,這時,編譯器在棧上分配了一塊空間,然後把Stamp_1.Age的值填進去,二者沒有任何關聯,就像在計算機中復制文件一樣,只是把Stamp_1.Age的值拷貝給age了。而引用類型則不同,在聲明guru時把Stamp_2賦給它,前面說過,引用類型包含的只是堆上數據區域地址的引用,其實就是把Stamp_2的引用也賦給guru,因此它們指向了同一塊內存區域。既然是指向同一塊區域,不管修改誰,另一個的值都會跟著改變,就像信用卡跟親情卡一樣,用親情卡取了錢,與之關聯的信用卡賬上也會跟著發生變化。

作者:耑新新,發布於 博客園

轉載請註明出處,歡迎郵件交流:[email protected]

淺談C#中的值類型和引用類型