首先看一看什麼是裝箱和拆箱?
簡單的來說:
將是價值型別轉換為參考型別;
拆箱是指引用型別轉換為值型態轉換為值型。
值類型,包含原始類型(Sbyte、Byte、Short、Ushort、Int、Uint、Long、Ulong、Char、Float、Double、Bool、Decimal)、枚舉 (enum) 、結構 (struct)。
引用型別包括類別、陣列、介面、委託、字串等。
裝箱:值類型到引用型別或任何到此值類型所實現的任何介面類型的隱含轉換
temp: int temp = 3;
temp ,temp為值類型,在堆疊中分配;當分配obj這個引用類型時,我們需要在堆中分配一個obj對象,然後把temp值賦給它,這麼一系列的過程就是裝箱的過程。
例如:int temp = 3;
System.Object ob
拆箱過程中,先確定物件obj為一個值類型的裝箱值,然後將值賦給值類型。
隱式轉換總是會成功的情況,不會拋出異常:
(1)、從派生類別到基底類別;
(2)、從派生介面到基底介面;
(3)、從類別到介面(此類別實作了介面);
(4)、從Null到任何類別;
明確參考轉換,以下可能拋出異常,轉換不一定成功:
(1)、從基底類別到衍生類別;
(2 )、從介面到介面(基底介面到衍生介面或兩個介面沒有關係);
(3)、從介面到類別(此類別實作了該介面或該類別未封閉);
(4)、從類別到介面(該類別未實現此介面且該類別未封閉);
上面簡單的介紹了拆箱和裝箱的定義,下面就來討論一下裝箱和拆箱與堆和棧怎樣使用
比較裝箱和拆箱的優缺點
裝箱和拆箱雖然滿足了兩種類型之間的轉換。但是從裝箱的過程中不難看出,每次裝箱時要在堆中new一個新的對象,當量特別大是肯定會大大影響程式的效率。事物總有兩面性,every sword has two sides,事情便簡單了,性能也下來了。所以,在應用中,我們應該盡量避免裝箱操作。
了解了裝箱和拆箱的操作,我們可以清楚的明白:裝箱操作會導致資料在堆和棧上進行拷貝,頻繁的裝箱操作會性能損失。而相較而言拆箱過程對效能損耗還是比較小的。
裝箱與拆箱的詳細步驟
1、裝箱(box)的詳細步驟:
(1)、在堆上分配一個記憶體空間,大小等於需要裝箱的值類型物件的大小加上兩個引用型別物件都擁有的成員:型別物件指標與同步區塊引用。
(2)、將堆疊上的值類型物件複製到堆疊上新分配的物件。
(3)、回傳一個指向堆上新物件的引用,並且儲存到堆疊上被裝箱的那個值類型的物件裡。
這個步驟不需要程式設計師自己寫,任何出現裝箱的地方,編譯器會自動加上執行上述功能的IL程式碼。
所謂的拆箱是裝箱對應著的概念,但拆箱的過程和裝箱並不是倒過來就是:
2、收箱(unbox.any)的詳細步驟 2、 拋出NullReferenceException異常。
如果引用指向的不是期望對象的已裝箱對象,則拋出InvalidCastException異常。
(1)、取得已裝箱物件中各個欄位的位址,這個過程就是「拆箱」
需要說明的是一般拆箱以後會伴隨著物件的拷貝,但拷貝作業已經不是拆箱的範疇。
(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("数据已经装箱!"); } //我们在这里更改i的值 i = 33; Console.WriteLine("int i现在的值是:{0}",i); Console.WriteLine("int i装箱的值是:{0}",obj); } }
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());