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

數據的類型定義了存儲數據須要的內存大小及組成該類型的數據成員。類型還決定了對象在內存中的存儲位置——棧或堆。函數

類型被分爲兩種:值類型和引用類型,這兩種類型的對象在內存中的存儲方式不一樣。ui

  • 值類型只須要一段單獨的內存,用於存儲實際的數據。
  • 引用類型須要兩段內存。
    • 第一段存儲實際的數據,它老是位於堆中。
    • 第二段是一個引用,指向數據在堆中的存放位置。

下圖展現了每種類型的單個數據項是如何存儲的。對於值類型,數據存放在棧裏。對於引用類型,實際數據存放在堆裏而引用存放在棧裏。3d

數據的存儲

值類型

全部值類型都隱式派生自 System.ValueType,下表顯示 C# 值類型:code

值類型 類別 類型後綴
bool Boolean
byte 無符號、數字、整型
char 無符號、數字、整型
decimal 數字、浮點 Mm
double 數字、浮點 Dd
enum 枚舉
float 數字、浮點 Ff
int 帶符號、數字、整型
long 帶符號、數字、整型 Ll
sbyte 帶符號、數字、整型
short 帶符號、數字、整型
struct 用戶定義的結構
uint 無符號、數字、整型 Uu
ulong 無符號、數字、整型 ULUluLulLULulUlu
ushort 無符號、數字、整型

值類型直接包含值,換言之,變量引用的位置就是內存中實際存儲值的位置。對象

所以,將一個值賦給變量 1,再將變量 1 賦給變量 2,會在變量 2 的位置建立值的拷貝,而不是引用變量 1 的位置。blog

這進一步形成更改變量 1 的值不會影響變量 2 的值。內存

下圖對此進行了演示。number1 引用內存中的特定位置,該位置包含值 42。將 number1 的值賦給 number2 以後,兩個變量都包含值 42。但修改其中任何一個值都不會影響另外一個值。ci

值類型的實例直接包含數據

相似地,將值類型的實例傳給 Console. WriteLine() 這樣的方法也會生成內存拷貝。在方法內部對參數值進行的任何修改都不會影響調用函數中的原始值。get

引用類型

引用類型的變量存儲對數據存儲位置的引用,而不是直接存儲數據。要去那個位置才能找到真正的數據。因此爲了訪問數據,「運行時」1 要先從變量中讀取內存位置,再「跳轉」到包含數據的內存位置。it

爲引用類型的變量分配實際數據的內存區域稱爲堆(heap)。

引用類型的實例指向堆

因爲引用類型只拷貝對數據的引用,因此兩個不一樣的變量可引用相同的數據。所以,對一個變量執行的操做會影響另外一個變量所引用的對象。不管賦值仍是方法調用都會如此。所以,若是在方法內部更改引用類型的數據,方法執行完成以後,將看到更改後的結果。

總結

一個類型要麼是值類型,要麼是引用類型。區別在於數據存儲的方式:對於值類型,數據存放在棧裏。對於引用類型,實際數據存放在堆裏而引用存放在棧裏。

引用類型的變量存儲對其數據(對象)的引用,而值類型的變量直接包含其數據。 對於引用類型,兩個變量可引用同一對象;所以,對一個變量執行的操做會影響另外一個變量所引用的對象。 對於值類型,每一個變量都具備其本身的數據副本,對一個變量執行的操做不會影響另外一個變量。


  1. 「運行時」的內容請參考這篇文章:https://www.vinanysoft.com/c-sharp-basics/introducing/managed-execution-and-the-common-language-infrastructure/

相關文章
相關標籤/搜索