這邊提供一個小小記憶法, 就是..., 圖像記憶法 !
總之裝箱的過程, 就是 boxing, 就是放到一個隱含的型別中: System.Object, 那你是不是就看不到了呢 ? 你應該就看不到了, 因為他就是被一個 box 裝起來了, 你看不到他, 你看不到他, 你看不到他。
中文翻譯如其名 boxing 就是裝箱, unboxing 就是拆箱; 然而他的用途或特色呢 ? 網路上有很多資料, 喜歡哪一種講法就看個人, 我的歸納重點。
- 易於指標操作
- 多型的操作彈性
- 注意副效應 (性能消耗與轉型錯誤)
易於指標操作
來看看這個很像 C++ 的指標操作代碼。long num1;
long num2 = num1;
long* ptr1 = &num1; //address-of operator &
這個例子剛好是 long, 但他可以是任意型別。num1 是長整數占用 8 bytes 記憶體; 而 ptr1 是個指標變數占用 4 bytes 記憶體。也就是說, 不管資料型別為何或 size 多大, 他被 assign 給某個變數 (num2) 或指標變數 (ptr1) 後, 這個變數本身所需要占據的記憶體就剩 4 bytes 的指標位址 (而資料儲存的地方是另外一回事), 後續拷貝變數, 傳遞變數, 成本都低的非常多 (想像當資料 size 很大時)。是不是稍微可以了解為何會有 reference type 了呢 ? 如 string, object。多型的操作彈性
boxing 是轉為 System.Object 型別的物件, 是所有類別的母類別, 在進行資料結構設計就出現一種多型的技巧, 如 List<object> 的 Item 與 Dictionary<string, object> 的 Item.Value, 可以吃下各類型的實體; 當然, 也可以是 List<BaseClass>, Dictionary<string, BaseClass>, 不需要非常清楚知道子類別 runtime 型別, 只需要繼承某個母類別, 就可以針對這個物件進行轉型或統一的行為操作了, 是一種抽象設計。當然, 這裡的範例指的是編程語言如 C++, Java, C#; 至於 Python, php, JavaScript 等腳本語言本身就支持類似 a = [ '1', 2, 3.0, [] ] 這種操作。注意副效應 (性能消耗與轉型錯誤)
型別轉換 就是常聽到的 casting 或是 type conversion, 是要消耗 cpu 資源的, 運氣好一點是編譯器會告知你 A 不能轉 B, 運氣差就是 runtime 錯誤了, 所以千萬別太任性的轉換, 應要有適量的抽象化設計, 清楚的註解, 否則當你看到一堆 object 或 dynamic 型別的物件, 接手的人應該會譙翻天, 尤其還耗效能。用數據來佐證好了, 寫三個很簡單的 function, 各寫一行 assign 行為 : 1). 無 casting, 2). casting 為 object, 3). casting 為 long, 跑 1000 萬次來測試性能上的差異。
public static void WithoutBox(long s)
{
long l1 = s;
}
public static void Boxing(long s)
{
object o = s;
}
public static void UnBoxing(object s)
{
long l2 = (long)s;
}
是不是發現, 只是一個 long 型別轉來轉去, 不轉換的 WithougBox() 與其他要轉換的性能快 1 倍以上, 而 unboxing 又比 boxing 快。尤其 unboxing 還會有 System.InvalidCastException 的錯誤機率, 比效能危害更大。
程式筆記
如果有人喜歡用程式碼來記憶, 也沒關係, 擷取 MSDN 官網的 程式碼 片段, 短短三行就行了。int i = 123; // a value type
object o = i; // boxing
int j = (int)o; // unboxing
參考資料
- https://msdn.microsoft.com/zh-tw/library/system.object(v=vs.110).aspx
- https://msdn.microsoft.com/en-us/library/system.invalidcastexception(v=vs.110).aspx
- https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/types/boxing-and-unboxing
- https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/unsafe-code-pointers/how-to-obtain-the-address-of-a-variable
- https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/types/casting-and-type-conversions
- https://stackoverflow.com/questions/2111857/why-do-we-need-boxing-and-unboxing-in-c
Comments
Post a Comment