裝箱與拆箱的執行個體教程

來源:互聯網
上載者:User
裝箱:實值型別比參考型別“輕”,原因是他們不作為對象在託管堆中分配,不被記憶體回收,也不通過指標進行引用。但是許多時候都需要擷取實值型別的引用,例如,假定要建立ArrayList對象來容納一組point結構,代碼如下:public sealed class Program{public static void Main(){ArrayList a = new ArrayList();Point p; //分配一個Point(不在堆中分配)for (int i = 0; i < 10; i++){p.x = p.y = i; //初始化實值型別中的成員a.Add(p); //對實值型別裝箱,將引用添加到ArrayList中}}} 每次迴圈迭代都初始化一個ponit的實值型別欄位,並將該point儲存到ArrayList中。但思考一下ArrayList中究竟儲存了什嗎?是Point結構,Point結構的地址,還是其他完全不同的東西?要知道正確答案,必須研究ArrayList的Add方法,瞭解他的參數被定義成什麼類型。本例的Add方法原型如下:public virtual int Add(Object value);可以看出Add擷取的是一個Object參數,也就是說,Add擷取對託管堆上的一個對象的引用來作為參數。但之前的代碼傳遞的是p,也就是一個Point,是實值型別。為了使代碼正確工作,Point實值型別必須轉成真正的,在堆中託管的對象,而且必須擷取對該對象的引用。 將實值型別轉換成參考型別要使用裝箱機制。下面說說對實值型別的執行個體進行裝箱時發生的事情:1,在託管堆中分配記憶體。分配的記憶體量是實值型別各欄位所需的記憶體量,還要加上託管堆所有對象都有的兩個額外成員(類型對象指標和同步塊索引)所需要的記憶體量2,實值型別的欄位複製到新分配的堆記憶體3,返回對象地址。現在該對象是對象引用;實值型別成了參考型別C#編譯器檢測到上述代碼是向要求參考型別的方法傳遞實值型別,所以自動產生代碼對對象進行裝箱。所以在運行時,當前存在於Point實值型別執行個體p中的欄位複製到新分配的Point對象中。已裝箱Point對象(現在是參考型別)的地址返回並傳給Add方法。Point對象一直存在於堆中,直至被記憶體回收。Point實值型別變數p可被重用,因為ArrayList不知道關於他的任何事情。在這種情況下,已裝箱類型的生存期超過了為裝箱實值型別的生存期。 拆箱:假定要用一下代碼擷取ArrayList的第一個元素:Point p=(Point)a[0];他擷取ArrayList的元素0包含的引用,視圖將其放到Point實值型別的執行個體p中。為此,已裝箱Point對象中的所有欄位都必須複製到實值型別變數中,後者線上程棧上。CLR分兩步完成複製。第一步擷取已裝箱Point對象中的各個Point欄位地址。這個過程稱為拆箱。第二部將欄位包含的值從堆複製到基於棧的實值型別執行個體中 拆箱不是直接將裝箱過程倒過來。拆箱的代碼比裝箱低得多。拆箱其實就是擷取指標的過程,該指標指向包含在一個對象中的原始實值型別。其實,指標指向的是已裝箱執行個體中的未裝箱部分。所以和裝箱不同,茶香不要求在記憶體中複製任何位元組,知道這個重要區別後,還應知道的一個重點是,往往緊接著一次欄位複製。已裝箱實值型別執行個體在拆箱是,內部發生下面這些事情:1,如果包含“對已裝箱實值型別的引用”的變數為null,拋出NullReferenceException異常2,如果引用的對象不是所需實值型別的已裝箱執行個體,拋出InvalidCastException異常 第二條意味著一下代碼的工作方式和你想的可能不一樣:public static void Main(){Int32 x = 5;Object o = x; //對x裝箱,o引用已裝箱對象Int16 y = (Int16)o; //拋出InvalidCastException異常}從邏輯上說,完全能擷取o引用的已裝箱Int32,將其強制轉換為int16.但是對對象進行拆箱時,只能轉型為最初未裝箱的實值型別--本例Int32,以下是正確寫法:public static void Main(){Int32 x = 5;Object o = x; //對x裝箱,o引用已裝箱對象Int16 y = (Int16)(Int32)o; //先拆箱為正確類型,再轉型}在看以下代碼:public static void Main(){Point p;p.x = p.y = 1;Object o = p; //對p裝箱,o引用已裝箱執行個體 //將Point的x欄位變成2p = (Point)o; //對o拆箱,將欄位從已裝箱的執行個體複製到棧變數中p.x = 2; //更改棧變數的狀態o = p; //將p裝箱,o引用新的已裝箱執行個體}最後三行代碼的唯一目的就是將Point的x欄位從1變成2.為此,首先要執行一次拆箱,在執行一次欄位複製,再更改欄位(棧上),最後執行一次裝箱(在託管堆上建立全新的已裝箱執行個體)。由此可以看出裝箱拆箱對應用程式效能的影響。問:public static void Main(){Int32 v = 5;Object o = v;v = 123;Console.WriteLine(v+","+(Int32)o);}上述代碼發生了多少次裝箱?
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.