上一篇簡單述說了值類型與引用類型的關系,那麼不能不說說值類型的拆箱與裝箱:
將值類型裝箱就相當於把它包裝起來給人看,"你瞧,我現在是引用類型了",顧名思義拆箱就是將包裝卸下來"其實我是值類型"。
在將值類型利用裝箱機制打包成引用時他要進行許多的打扮:
1.首先要給他一個空間(在托管堆中分配內存),多大呢,要必須要容得下包裝所需要的物件化妝品之類的(各自段所需的內存量),此外還要有專家設計師吧(類型對象指針和同步塊索引兩個額外的成員);
2.空間有了,他就要開始將自己的東西和物件搬過來(只類型的字段復制到新分配的堆內存);
3.一切准備就緒,不過此時出了意外,他被人頂替冒充了,而冒充它的那個人很清楚這個房間的位置(返回對象地址,改地址就是對象引用)。
上面解釋可能會有點牽強,給個例子一目了然:
1 struct Point{public int x,y;}
2 public sealed class Program{ 3 public static void Main() 4 { 5 ArrayList a = new ArrayList(); 6 Point p; 7 p.x=1;p.y=1; 8 a.Add(p); 9 } 10 }
最簡單不過的代碼了,由於Add()方法參數是Object類型,所以在執行時要進行一次裝箱操作:Point值類型實例p中的字段會復制到新分配的Point對象中,已裝箱的Point對象的地址返回並傳給Add方法,需要說明的是Point對象此時是引用類型存在於堆中,Point值類型變量p可被重用,a已經不知道他的任何事情,由此可見已裝箱值類型生存期超過了未裝箱值類型的生存期。
-------------------------------------------------------------------------------
接下來說說拆箱:
緊接上段代碼,如若Point p = (Point)a[0];代碼執行時,就進行了一次拆箱:
一個人他知道了那個房間的地址,他把東西都要了回來,而東西可能已經變了(拆箱不是簡單的裝箱逆過程,它的代價比裝箱要低,拆箱就是獲取指針的過程,該指針指向包含在一個對象中的原始值類型(數據字段),指針指向的是已裝箱實例中未裝箱的部分,不要求在內存中復制任何字節);
拆箱時要注意:1.包含"對已裝箱類型實例的引用"的變量為null時,會拋出異常(他都沒有房間,也沒有物件,你找個P啊)
2.如果引用的對象不是所需值類型的已裝箱實例,拋出異常(張三的東西,李四來要,對方能給嗎);
--------------------------------------------------------------------------------
下面來做個腦筋急轉彎:
1 public static void Main(){ 2 int v=5; 3 Object o = v; 4 v=123; 5 Console.WriteLine(v+","+(int)o); 6 }
問:上面代碼發生了多少次裝箱?想好在打開。。。
三次,一次很好理解,剩下的兩次,對比Console.WriteLine參數即可理解 View Code
部分內容參考自《CLR C#》