黑马程序员技术交流社区

标题: 装箱问题研究 [打印本页]

作者: 张林杰    时间: 2013-10-11 12:29
标题: 装箱问题研究
本帖最后由 张林杰 于 2013-10-14 21:04 编辑

问题一:在MSDN中,装箱的定义是:装箱是将值类型转换为 object 类型或由此值类型实现的任一接口类型的过程。
             链接:http://msdn.microsoft.com/zh-cn/library/vstudio/yz2be5wk.aspx
             按我的理解,装箱的定义是:装箱就是值类型转换为引用类型的过程,并且两种类型存在继承关系(我这样理解对吗?)。
             所以问题为:下面的式子有没有发生装箱、拆箱?
  1. //问题1.1
  2. int a=1;
  3. ValueType vt=a;//值类型隐式继承自System.ValueType 类型,该类型为引用类型
  4. int b=(int)vt;
复制代码
问题二:装箱会在堆中新开内存,而且拆箱的强制转换很消耗时间,所以避免装拆箱,最好是函数的重载以及使用泛型,
             就如Console.WriteLine()方法。此部分问题来源于:
             http://www.cnblogs.com/wenjiang/archive/2013/03/14/2959466.html 这篇文章值得一读
             问题是:以下式子会发生装拆箱吗?
  1. //问题2.1
  2. int n=1;
  3. Console.WriteLine(n);
复制代码
  1. //问题2.2
  2. int m=1;
  3. Console.WriteLine("{0}",m);
复制代码
  1. //问题2.3
  2. int number = 5;
  3. Object obj = number;
  4. number = 10;
  5. Console.WriteLine(number + "," + (int)obj);//原文中的解释没看懂...
复制代码
  1. //问题2.4
  2. int a=1;
  3. string b=a.ToString();//a重写了基类ValueType的Tostring()方法?那此处发生装箱吗...
复制代码
暂时就这样,欢迎大家解答~






作者: ╰┄轩、辕_ヤ    时间: 2013-10-11 13:41
我所知道的:
装箱和拆箱使值类型能够被视为对象,对值类型装箱将把该值类型打包到Object引用类型的一个实例中。
问题2.3正好就是一个装箱和取消装箱的操作


作者: 面朝大海,春暖    时间: 2013-10-11 15:06
本帖最后由 面朝大海,春暖 于 2013-10-11 15:16 编辑

问题一:不会,既然装箱的定义是:装箱是将值类型转换为 object 类型,object是所有类的基类,因此包括System.ValueType ,那么ValueType 定义的类型不一定是object类型,与定义不符,所以不会发生装箱、拆箱。
问题二:
只有2.3发生了装箱、拆箱。。取消装箱即拆箱,正常的拆箱:int num=(int)obj;2.3中只是没赋给新的变量而已。。

作者: 夏闯富    时间: 2013-10-12 11:23
本帖最后由 夏闯富 于 2013-10-12 11:32 编辑
  1. int i=123;
  2. object o=i;//隐示装箱
  3. object ol=(object)i;//显示装箱

  4. o=123;
  5. i=(int)o;//拆箱
复制代码
问题二不属于拆箱,那些只是调用的不同的WriteLine()的重载方法,变量没有做任何类型转换。

WriteLine()的重载.png (66.11 KB, 下载次数: 51)

WriteLine()全部重载

WriteLine()全部重载

作者: 张林杰    时间: 2013-10-12 16:04
先感谢楼上各位的回答,不过我还是认为问题一中应该是发生装箱了的,加入没有装箱,一个值类型怎么可以赋值给一个引用类型呢:  ValueType(引用类型) vt=a(值类型)(两者继承关系); 就像不能把int类型直接赋值给string,如int a=1;string b=a;(int和string无继承关系),既然可以复制,说明就发生了装箱
作者: 张林杰    时间: 2013-10-12 16:10
夏闯富 发表于 2013-10-12 11:23
问题二不属于拆箱,那些只是调用的不同的WriteLine()的重载方法,变量没有做任何类型转换。
...

那比如问题2.2中int m=1;Console.WriteLine("{0}",m);
这个应该是调用public static void WriteLine(string format,object arg0);这个重载方法,那就是m(值类型)复制给arg0(object类型-就是引用类型),则发生了装箱
作者: 夏闯富    时间: 2013-10-12 19:33
本帖最后由 夏闯富 于 2013-10-12 19:54 编辑
张林杰 发表于 2013-10-12 16:10
那比如问题2.2中int m=1;Console.WriteLine("{0}",m);
这个应该是调用public static void WriteLine(stri ...


嗯,你说的 对,我重新看了一下:
问题2.1 没有发生装拆箱
问题2.2 发生了装箱
问题2.3 任何类型+"字符串"=字符串(String类型),相当于“任何类型”调用了ToString()方法(number.ToString()没有装箱操作,但(int)obj这一过程有拆箱操作)
问题2.4 不再仅是内存级别的转换,而是考虑数据意义的转换。它是一个加工、改造的过程。(有些有拆装箱,有些无拆装箱;此处是int强制转换到string,无拆装箱)
作者: 张林杰    时间: 2013-10-14 00:22
额,再顶一下。。
作者: 夏闯富    时间: 2013-10-14 08:00
我也再帮你顶一个
作者: ˋ初°见    时间: 2013-10-14 20:17
装箱(boxing,box)        将值类型赋值给引用类型, object o = 12;
拆箱(unboxing)        就是将装箱的值类型强转为对应的数据, int n = (int)o;

我是运行程序,用reflector编译器看拆箱和装箱的

1.png (39.26 KB, 下载次数: 60)

第一题

第一题

2.png (49.03 KB, 下载次数: 54)

第二题

第二题

3.png (80.35 KB, 下载次数: 57)

第三题

第三题

4.png (44.27 KB, 下载次数: 52)

第四题

第四题

12121.png (14.96 KB, 下载次数: 52)

如果没有relector,就用v上自带的IL反汇编工具

如果没有relector,就用v上自带的IL反汇编工具

作者: 张林杰    时间: 2013-10-14 20:41
ˋ初°见 发表于 2013-10-14 20:17
装箱(boxing,box)        将值类型赋值给引用类型, object o = 12;
拆箱(unboxing)        就是将装箱的值类型强转为对 ...

非常感谢:handshake
我明白了!
作者: ˋ初°见    时间: 2013-10-14 21:02
张林杰 发表于 2013-10-14 20:41
非常感谢
我明白了!

:loveliness:
作者: 张林杰    时间: 2013-10-14 21:03
问题总结:
通过IL代码分析如下,
问题1.1 发生了装拆箱,值类型到引用类型,并且存在继承关系
问题2.1 没有发生任何装拆箱,因为Console.WriteLine()方法进行了重载
问题2.2 发生了装箱,调用了public static void WriteLine(string format,object arg0);
问题2.3 发生了三次装箱,一次拆箱,因为Console.WriteLine(number + "," + (int)obj);最终调用了string.Contact()
问题2.4 没有发生任何装拆箱,int类型进行基类ToString方法的重写,并没有转换为基类




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2