裝箱和拆箱幾乎是全部面試題中必考之一,看上去簡單,就每每容易被忽視。其實它一點都不簡單的,一個簡單的問題也能夠從多個層次來解讀。html
1.什麼是拆箱和裝箱?面試
2.什麼是箱子?性能
3.箱子放在哪裏?學習
4.裝箱和拆箱有什麼性能影響?編碼
5.如何避免隱身裝箱?spa
6.箱子的基本結構?指針
7.裝箱的過程?code
8.拆箱的過程?orm
9.下面這段代碼輸出什麼?共發生多少次裝箱?多少次拆箱?htm
int i = 5; object obj = i; IFormattable ftt = i; Console.WriteLine(System.Object.ReferenceEquals(i, obj)); Console.WriteLine(System.Object.ReferenceEquals(i, ftt)); Console.WriteLine(System.Object.ReferenceEquals(ftt, obj)); Console.WriteLine(System.Object.ReferenceEquals(i, (int)obj)); Console.WriteLine(System.Object.ReferenceEquals(i, (int)ftt));
有拆必有裝,有裝必有拆。
在上一文中咱們提到,全部值類型都是繼承自System.ValueType,而System.ValueType又是來自何方呢,不難發現System.ValueType繼承自System.Object。所以Object是.NET中的萬物之源,幾乎全部類型都來自她,這是裝箱與拆箱的基礎。
特別注意的是,本文與上一文有直接關聯,須要先了解上一文中值類型與引用類型的原理,才能夠更好理解本文的內容。
拆箱與裝箱就是值類型與引用類型的轉換,她是值類型和引用類型之間的橋樑,他們能夠相互轉換的一個基本前提就是上面所說的:Object是.NET中的萬物之源
先看看一個小小的實例代碼:
int x = 1023; object o = x; //裝箱 int y = (int) o; //拆箱
裝箱:值類型轉換爲引用對象,通常是轉換爲System.Object類型或值類型實現的接口引用類型;
拆箱:引用類型轉換爲值類型,注意,這裏的引用類型只能是被裝箱的引用類型對象;
因爲值類型和引用類型在內存分配的不一樣,從內存執行角度看,拆箱與裝箱就勢必存在內存的分配與數據的拷貝等操做,這也是裝箱與拆箱性能影響的根源。
int x = 1023; object o = x; //裝箱
裝箱就是把值類型轉換爲引用類型,具體過程:
如上圖所示,裝箱後內存有兩個對象:一個是值類型變量x,另外一個就是新引用對象o。裝箱對應的IL指令爲box
,上面裝箱的IL代碼以下圖:
int x = 1023; object o = x; //裝箱 int y = (int) o; //拆箱
明白了裝箱,拆箱就是裝箱相反的過程,簡單的說是把裝箱後的引用類型轉換爲值類型。具體過程:
如上圖所示,拆箱後,獲得一個新的值類型變量y,拆箱對應的IL指令爲unbox
,拆箱的IL代碼以下:
經過上面深刻了解了裝箱與拆箱的原理,不難理解,只有值類型能夠裝箱,拆的就是裝箱後的引用對象,箱子就是一個存放了值類型字段的引用對象實例,箱子存儲在託管堆上。只有值類型纔有裝箱、拆箱兩個狀態,而引用類型一直都在箱子裏。
之因此關注裝箱與拆箱,主要緣由就是他們的性能問題,並且在平常編碼中,常常有裝箱與拆箱的操做,並且這些裝箱與拆箱的操做每每是在不經意時發生。通常來講,裝箱的性能開銷更大,這不難理解,由於引用對象的分配更加複雜,成本也更高,值類型分配在棧上,分配和釋放的效率都很高。裝箱過程是須要建立一個新的引用類型對象實例,拆箱過程須要建立一個值類型字段,開銷更低。
爲了儘可能避免這種性能損失,儘可能使用泛型,在代碼編寫中也儘可能避免隱式裝箱。
就是不經意的代碼致使屢次重複的裝箱操做,看看代碼就好理解了
int x = 100; ArrayList arr = new ArrayList(3); arr.Add(x); arr.Add(x); arr.Add(x);
這段代碼共有多少次裝箱呢?看看Add方法的定義:
再看看IL代碼,能夠準確的獲得裝箱的次數:
顯示裝箱能夠避免隱式裝箱,下面修改後的代碼就只有一次裝箱了。
int x = 100; ArrayList arr = new ArrayList(3); object o = x; arr.Add(o); arr.Add(o); arr.Add(o);
裝箱就是值類型轉換爲引用類型,拆箱就是引用類型(被裝箱的對象)轉換爲值類型。
就是引用類型對象。
託管堆上。
裝箱和拆箱都涉及到內存的分配和對象的建立,有較大的性能影響。
編碼中,多使用泛型、顯示裝箱。
上面說了,箱子就是一個引用類型對象,所以她的結構,主要包含兩部分:
int i = 5; object obj = i; IFormattable ftt = i; Console.WriteLine(System.Object.ReferenceEquals(i, obj)); Console.WriteLine(System.Object.ReferenceEquals(i, ftt)); Console.WriteLine(System.Object.ReferenceEquals(ftt, obj)); Console.WriteLine(System.Object.ReferenceEquals(i, (int)obj)); Console.WriteLine(System.Object.ReferenceEquals(i, (int)ftt));
上面代碼輸出以下,至於發生多少次裝箱多少次拆箱,你猜?
False
False
False
False
False
版權全部,文章來源:http://www.cnblogs.com/anding
我的能力有限,本文內容僅供學習、探討,歡迎指正、交流。
.NET面試題解析(00)-開篇來談談面試 & 系列文章索引
書籍:CLR via C#
書籍:你必須知道的.NET
1.4.2 裝箱和拆箱:http://book.51cto.com/art/201012/237726.htm