概念
- 装箱在值类型向引用类型转换时发生,在堆中分配。
- 拆箱在引用类型向值类型转换时发生。
示例
装箱
public void BoxIn() { object tempObj = 4; }
示意:将整型常量1赋给object类型的变量obj;值类型是要放在栈上的,而object是引用类型,它需要放在堆上;要把值类型放在堆上就需要执行一次装箱操作。
- 利用ildasm 查看IL代码
.method public hidebysig instance void BoxIn() cil managed { // Code size 8 (0x8) .maxstack 2 .locals init (object V_0)/*声明object类型的名称为objValue的局部变量 */ IL_0000: ldc.i4.4 /*小于8大于0的情况下用的是ldc.i4 num ,而大于8 和小于0又是针对32位(在64 位下还有ldc.i8 num )的机器编程就用 ldc.i4.s num */; IL_0001: box [mscorlib]System.Int32 /*执行IL box指令,在内存堆中申请System.Int32类型需要的堆空间*/ IL_0006: stloc.0 /*弹出堆栈上的变量,将它存储到索引为0的局部变量中*/ IL_0007: ret } // end of method Test::BoxIn
拆箱
public void BoxOut() { object tempObj = 9; int tempInt = (int)tempObj; }
示意:首先进行一次装箱操作将整形数字装箱成引用类型;然后又执行一次拆箱操作,将存储到堆上的引用变量tempObj存储到局部整形值类型变量tempInt 中。
- 同理利用ildasm 查看IL代码
.method public hidebysig instance void BoxOut() cil managed { // Code size 16 (0x10) .maxstack 2 .locals init (object V_0, int32 V_1) IL_0000: ldc.i4.s 9 IL_0002: box [mscorlib]System.Int32 IL_0007: stloc.0 /*运行原理同上*/ IL_0008: ldloc.0 /*将索引为0的局部变量(即tempObj变量)压入栈*/ IL_0009: unbox.any [mscorlib]System.Int32 /*执行拆箱指令将引用类型object转换成System.Int32类型*/ IL_000e: stloc.1/*将栈上的数据存储到索引为1的局部变量即tempInt*/ IL_000f: ret } // end of method Test::BoxOut
结论
可见,执行装箱操作时不可避免的要在堆上申请内存空间,并将堆栈上的值类型数据复制到申请的堆内存空间上,因此消耗内存和cpu资源。可以用泛型来解决这问题。