標籤:style blog http color 使用 strong
在實際編碼過程中,有時候會出現裝箱和拆箱操作。下面就類分別認識一下:
需要注意的是,類型轉換和這個是不同的。Convert方法並沒有發生裝箱和拆箱操作,而是類型轉換,包括int.parse等等。
裝箱,是把實值型別拷貝了一個副本放在堆記憶體中。
拆箱,在參考型別直接找到實值型別儲存的位置(Person對象是參考型別,但其Age屬性是實值型別,也儲存在堆記憶體中),實際上我們往往拆箱後會用一個實值型別變數接收它。
例1:
1 int n = 10;2 Console.WriteLine(n);3 object o = n;//一次裝箱4 Console.WriteLine((int)o);5 Console.WriteLine(o);//這裡輸出的是字串"10",相當於Console.WriteLine(o.ToString());
上面的代碼中,第2句話並沒有發生裝箱,因為Console.WriteLine()方法有一個int類型重載;第3句話發生一次裝箱;而第4句話(int)o發生一次拆箱,拆箱後的值被其values接收,如果沒有Console.WriteLine()方法有一個int類型重載的話,會馬上再次裝箱,因為這個重載,沒有發生裝箱;最後1句話,輸出的是字串"10",相當於Console.WriteLine(o.ToString())。所以在判斷一句話是否發生裝箱和拆箱要結合建構函式來看。
例2:
1 int n = 10;2 3 IComparable com = n;4 5 int m = (int)com;6 7 Console.WriteLine(m);
上面的代碼中,第二句話發生了裝箱,第三句話發生了拆箱,因為int類型實現了IComparable介面。
例3:
1 int d = 999;2 object o = d; //裝箱3 4 //裝箱時使用什麼類型,拆箱時也必須使用同樣的類型。否則報異常5 double d1 = (double)o; //拆箱
6 Console.WriteLine(d1);
例3中,編譯會報錯,以為在第2句話裝箱前是int類型,而拆箱時確是double。需要注意的是,裝箱前是什麼類型,拆箱後也必須是什麼類型,否則會報錯。
例4:
1 int n = 100; 2 M1(n); 3 4 string x = "a"; 5 double d1 = 10; 6 string y = "b"; 7 int n1 = 9; 8 string z = "c"; 9 string full = x + d1 + y + n1 + z;10 Console.WriteLine(full);11 12 //定義函數如下:13 static void M1(double d)14 {15 Console.WriteLine(d);16 }17 18 static void M1(object o)19 {20 Console.WriteLine(o);21 }
上面的代碼到底發生了幾次裝箱和拆箱呢?首先看M1()方法,經反編譯得知M1((double) n);由此可見,M1()方法並沒有去找object類型的重載,而是找了與之相近的double類型重載,所以沒有發生裝箱。第9句話經反編譯得知Console.WriteLine(string.Concat(new object[] { x, d1, y, n1, z }));它將double類型變數d1和int類型變數n1裝箱成object類型。所以上面的代碼只發生了2次裝箱。
裝箱和拆箱帶來的效能影響:
日常編碼中應避免裝箱和拆箱,因為他們會帶來效能的損耗。看下面的代碼:
1 ArrayList aList = new ArrayList();2 Stopwatch sw = new Stopwatch();3 sw.Start();4 for (int i = 0; i < 100000; i++)5 {6 aList.Add(i); //Add方法每添加一次發生一次裝箱7 }8 sw.Stop();9 Console.WriteLine("用時:"+sw.Elapsed);
運行結果:
我們換另一種:
1 List<int> aList = new List<int>();2 Stopwatch sw = new Stopwatch();3 sw.Start();4 for (int i = 0; i < 100000; i++)5 {6 aList.Add(i); 7 }8 sw.Stop();9 Console.WriteLine("用時:" + sw.Elapsed);
運行結果:
由此可見,效能影響還是挺大的。
總結:
一)裝箱和拆箱的判斷依據:
1.發生在實值型別和參考型別之間;
2.具備父子類的關係。
二)判斷一句話是否發生裝箱和拆箱要結合建構函式來看;
三)裝箱前是什麼類型,拆箱後也必須是什麼類型,否則會報錯;
四)寫代碼的過程中應盡量避免裝箱和拆箱帶來的效能消耗。