輕松學(xué)習(xí)C#的裝箱與拆箱
首先看一看什么是裝箱和拆箱?
簡單的來說:
裝箱就是值類型轉(zhuǎn)換為引用類型;
拆箱就是引用類型轉(zhuǎn)換為值類型。
值類型,包括原類型(Sbyte、Byte、Short、Ushort、Int、Uint、Long、Ulong、Char、Float、Double、Bool、Decimal)、枚舉 (enum) 、結(jié)構(gòu) (struct)。
引用類型包括類、數(shù)組、接口、委托、字符串等。
裝箱:值類型到引用類型或到此值類型所實現(xiàn)的任何接口類型的隱式轉(zhuǎn)換
例如: int temp = 3;
System.Object obj = temp;
其中,temp為值類型,在棧中分配;當(dāng)分配obj這個引用類型時,我們需要在堆中分配一個obj對象,然后把temp值賦給它,這么一系列的過程就是裝箱的過程。
拆箱:從引用類型到任意值類型的顯式轉(zhuǎn)換。與裝箱不同,拆箱式顯示轉(zhuǎn)換。
例如:int temp = 3;
System.Object obj = temp;
int i = (int) obj;
拆箱過程中,首先來確定對象obj為一個值類型的裝箱值,然后把值賦給值類型。
隱式轉(zhuǎn)換總會成功的情況,不會拋出異常:
(1)、從派生類到基類;
(2)、從派生接口到基接口;
(3)、從類到接口(該類實現(xiàn)了接口);
(4)、從Null到任何類;
顯式引用轉(zhuǎn)換,以下可能拋出異常,轉(zhuǎn)換不一定成功:
(1)、從基類到派生類;
(2)、從接口到接口(基接口到派生接口或者倆接口沒有關(guān)系);
(3)、從接口到類(該類實現(xiàn)了該接口或該類未封閉);
(4)、從類到接口(該類未實現(xiàn)該接口且該類未封閉);
上面簡單的介紹了拆箱和裝箱的定義,下面就來討論一下裝箱和拆箱與堆和棧怎樣使用
其中值類型是在棧中分配內(nèi)存,本身的聲明就是一個初始化的過程,其不需要進行垃圾回收,只要超出所定義的作用范圍會自動釋放內(nèi)存,而引用類型則是在堆中分配的,和java一樣,在堆種分配內(nèi)存,而其托管堆進行垃圾回收。當(dāng)兩種數(shù)據(jù)類型進行轉(zhuǎn)換時就引出了裝箱/拆箱。
比較裝箱和拆箱的優(yōu)缺點
裝箱和拆箱雖然滿足了兩只類型之間的轉(zhuǎn)換。但是從裝箱的過程中不難看出,每次裝箱時要在堆中new一個新的對象,當(dāng)量特別大是肯定會大大影響程序的效率。事物總有兩面性,every sword has two sides,事情便簡單了,性能也下來了。所以,在應(yīng)用中,我們應(yīng)該盡量避免裝箱操作。
了解了裝箱和拆箱的操作,我們可以清楚的明白:裝箱操作會導(dǎo)致數(shù)據(jù)在堆和棧上進行拷貝,頻繁的裝箱操作會性能損失。而相比而言拆箱過程對性能損耗還是比較小的。
裝箱和拆箱的詳細步驟
1、裝箱(box)的詳細步驟:
(1)、在堆上分配一個內(nèi)存空間,大小等于需要裝箱的值類型對象的大小加上兩個引用類型對象都擁有的成員:類型對象指針和同步塊引用。
(2)、把堆棧上的值類型對象復(fù)制到堆上新分配的對象。
(3)、返回一個指向堆上新對象的引用,并且存儲到堆棧上被裝箱的那個值類型的對象里。
這個步驟不需要程序員自己編寫,在任何出現(xiàn)裝箱的地方,編譯器會自動加上執(zhí)行以上功能的IL代碼。
所謂的拆箱就是裝箱對應(yīng)著的概念,但拆箱的過程和裝箱并不是倒過來就是:
2、拆箱(unbox.any)的詳細步驟
如果為待拆箱對象為null,拋出NullReferenceException異常。
如果引用指向的不是一個期望對象的已裝箱對象,拋出InvalidCastException異常。
(1)、獲取已裝箱對象中各個字段的地址,這個過程就是“拆箱”
需要說明的是一般拆箱以后會伴隨著對象的拷貝,但拷貝操作已經(jīng)不是拆箱的范疇。
下面舉兩個小的例子來實現(xiàn)什么是裝箱、拆箱以及怎樣避免因頻繁的裝箱而耗費內(nèi)存
(1)、裝箱:
using System; public class Test { public static void Main(String[] args) { int i = 10; //將值類型的i裝箱 //需要注意的是:這里的裝箱采用的是值的拷貝 object obj = i; //檢驗是否裝箱成功了 if(obj is int) { Console.WriteLine("數(shù)據(jù)已經(jīng)裝箱!"); } //我們在這里更改i的值 i = 33; Console.WriteLine("int i現(xiàn)在的值是:{0}",i); Console.WriteLine("int i裝箱的值是:{0}",obj); } }
(2)、拆箱:
int i = 10; object obj = i; int j = (int)obj; (3)、避免頻繁的裝箱: int i = 10; int j = 20; int s = 30; Console.WriteLine("i的值為{0},j的值為{1},s的值為{2}", i.ToString(), j.ToString(), s.ToString());
以上就是介紹了C#的裝箱與拆箱,思路很清晰,涉及的內(nèi)容很全面,包括裝箱和拆箱的優(yōu)缺點、裝箱和拆箱的步驟等,很適合初學(xué)者進行學(xué)習(xí)。
相關(guān)文章
Unity Shader實現(xiàn)動態(tài)霧效果
這篇文章主要為大家詳細介紹了Unity Shader實現(xiàn)動態(tài)霧效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-04-04C# 無需COM組件創(chuàng)建快捷方式的實現(xiàn)代碼
做一個小程序, 需要創(chuàng)建快捷方式, 網(wǎng)上普遍的做法是引入 COM 組件, 雖然也挺方便的, 但引入之后, 程序就需要多帶一個 dll 文件, 這樣, 想做成單文件便攜版就不行了2011-05-05Unity通過腳本創(chuàng)建網(wǎng)格Mesh的方法
Unity中的網(wǎng)格作為組件不能脫離物體單獨存在,通過新建腳本來實現(xiàn)相關(guān)操作,本文重點給大家介紹Unity通過腳本創(chuàng)建網(wǎng)格Mesh的方法,感興趣的朋友一起看看吧2022-04-04用序列化實現(xiàn)List<T> 實例的深復(fù)制(推薦)
下面小編就為大家?guī)硪黄眯蛄谢瘜崿F(xiàn)List<T> 實例的深復(fù)制(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02