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

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

  • 概念

值類型直接存儲其值。

引用類型存儲對值的引用。

說起來有些拗口,其本質是ValueReference的區別,在文檔翻譯過程中也有譯者將Reference翻譯為參考。兩種類型在內存中的存儲方式有顯著區別。

  • 不同的存儲對象

值類型變量存儲的是變量的值,直接儲存在棧內存中。

引用類型變量存儲的是變量所在的內存地址,引用類型變量的實際數據存儲于托管堆,變量本身僅僅是一個指向堆中實際數據的地址,存儲于棧內存中,通常是四個字節。

  • 不同的存儲位置

值類型Value存儲在線程堆棧中

引用類型Reference存儲在托管堆上

內存格局通常劃分為四個區:

全局數據區:存放全局變量,靜態數據,常量

代碼區:存放所有的程序代碼

棧區:存放為運行而分配的局部變量,參數,返回數據,返回地址等

堆區:即自由存儲區

為了理解值類型變量和引用類型變量的內存分配模型,我們應先區分兩種不同的內存區域——線程堆棧Thread Stack和托管堆Managed Heap

每一個正在運行的程序都對應著一個進程Process,在一個進程內部,可以有一個或多個線程Thread,每個線程都擁有一塊“自留地”,成為線程堆棧,大小為1M,用于保存自身的一些數據,如函數中定義的局部變量、函數調用時傳送的參數值等。

現在我們可以解釋第一句話——值類型存儲在線程堆棧中,也就是說所有值類型的變量都是在線程堆棧中分配的。

另一塊內存區域稱為堆Heap,在.NET這種托管環境下,堆由CLR(Common Language Runtime)管理,所以又稱托管堆Managed Heap。例如使用new關鍵字創建類的對象實例時,分配給對象的內存單元就位于托管堆中。

  • 不同的類型

這里類型區分的對象是C#中內建的類型Type和用戶自定義的類型。

C#中的值類型:C#有15個預定義類型,其中13個是值類型,兩個是引用類型(stringobject)。

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

由此分類可以得知,struct是輕量級的類這句話本質上就不成立,兩者的內存模型和行為表現都有區別。

  • 不同的表現

1.值類型的表現

int a = 5;
int b = a;

上面這段代碼中我們賦予a一個常量值5,而賦予ba的值,這會在內存中兩個不同的地方存儲值20。我們改變a的值,不會影響b的值,這兩個值時獨立存儲的。可以在上述代碼之后改變a的值,輸出b的值進行查看。

2.引用類型的表現

首先創建一個簡單的類,只包含一個int類型的屬性。

    class TestRef
    {
        public int A { get; set; }
    }

主方法中與值類型的代碼類型:

        public static void Main(string[] args)
        {
            TestRef testA = new TestRef {A = 20};
            TestRef testB = testA;  // 將testA賦值給testB

            Console.WriteLine("Before:testA中A的值:{0}", testA.A);
            Console.WriteLine("Before:testB中A的值:{0}", testB.A);

            testB.A = 15;   // 改變testB的屬性值

            Console.WriteLine("After:testA中A的值:{0}",testA.A);
            Console.WriteLine("After:testB中A的值:{0}", testB.A);
            Console.ReadKey();
        }

運行結果如圖所示:


運行結果

可以看到testB改變了屬性值之后,testA的屬性值也隨之改變,這是由于這兩個對象只是一個指向堆內存的地址,實際指向的只有一份實際的值。

3.與null的關系
如果變量是引用類型變量,則可以將其值設置為null,表示它不引用任何對象(可以將理解為將指針指向空)。而值類型不能為null,這也是為什么值類型初始化時必須指定初始值或默認值。

  • 設計立足點

    大多數更復雜的數據類型,包括我們自己聲明的類都是引用類型。它們分配在堆中,其生存期可以跨多個函數調用,可以通過一個或幾個別名來訪問。CLR執行一種精細的算法,來跟蹤哪些引用變量仍是可以訪問的,哪些引用變量已經不能訪問了。CLR會定期刪除不能訪問的對象,把它們占用的內存返回給操作系統。這是通過垃圾收集器實現的。

    把基本類型規定為值類型,而把包含許多字段的較大類型(通常在有類的情況下)規定為引用類型,C#設計這種方式的原因是可以得到最佳性能。如果要把自己的類型定義為值類型,就應把它聲明為一個結構。

  • 深拷貝和淺拷貝

深拷貝——源對象與拷貝對象互相獨立,其中任何一個對象的改動都不會對另外一個對象造成影響。

淺拷貝——拷貝對象后,兩個對象并未完全“分離”,改變一個對象實際儲存的內容,則兩個對象同時被改變。

這種差異的產生,即是取決于拷貝子對象時復制內存還是復制指針。深拷貝為子對象重新分配了一段內存空間,并復制其中的內容;淺拷貝僅僅將指針指向原來的子對象。

我們假設有了一個對象orignalObj,并且對象orignalObj已經有了一些具體的值,現在我們想創建一個orignalObj的副本即對象copyObj,我們希望,操作對象copyObj的同時不改變對象orignalObj的值,也就是說對象a和對象b是兩個完全獨立的對象,這即是深拷貝。

當兩個對象指向同一個地址時,如果我們改變其中一個對象的值,另一個對象也被相應的改變,這即是淺拷貝。

  • 額外需要注意

(1)String字符串對象是引用對象,但是很特殊,它表現的如值對象一樣,即對它進行賦值,分割,合并,并不是對原有的字符串進行操作,而是返回一個新的字符串對象。但這其實是運算符重載的結果,將string實現為語義遵循一般的、直觀的字符串規則。 String對象被分配在堆上,而不是棧上。

(2)Array數組對象是引用對象,在進行賦值的時候,實際上返回的是源對象的另一份引用而已;因此如果要對數組對象進行真正的復制(深拷貝),那么需要新建一份數組對象,然后將源數組的值逐一拷貝到目的對象中。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

推薦閱讀更多精彩內容

  • 從三月份找實習到現在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發崗...
    時芥藍閱讀 42,327評論 11 349
  • Java8張圖 11、字符串不變性 12、equals()方法、hashCode()方法的區別 13、...
    Miley_MOJIE閱讀 3,720評論 0 11
  • __block和__weak修飾符的區別其實是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,352評論 0 6
  • 原來這個時候肯定早睡了,因為我有催眠神器——VOA,今天晚上沒有聽,一直在想學英語的事。能聽到窗外的雨聲,像背景音...
    愛如捕風閱讀 1,163評論 1 24
  • 1、工字搓背(100次) 感冒咳嗽的預防和治療、腎臟疾病、可增強體質,促進生長 2、搓 鼻翼 加速血液循環、預防...
    楊觀仙閱讀 423評論 0 1