[基础]装箱拆箱1

分类:.Net知识问答| 发布:camnprbubuol| 查看: | 发表时间:2011/4/7

 

提问:

首先我们来提两个疑问,我们自定义了一个类如Customclass类型,

Customclass myclass=new Customclass()

Object obj=myclass;

运行上面这段代码,我们会进行装箱操作吗?

 

基础知识:

.Net的类型分为两种,一种是值类型(Value Type ),另一种是引用类型(Reference Type)。这两个类型的本质区别,值类型数据是分配在栈中,而引用类型数据分配在堆上。那么如果要把一个值类型数据放到堆上,就需要装箱操作;反之,把一个放在堆上的值类型数据取出来,则需要进行拆箱操作。

说到具体程序代码上, 我们可以这样总结: 装箱是将值类型转换为引用类型 ;拆箱是在已装箱的前提下将引用类型转换为值类型.

我们要充分的了解装箱和拆箱,首先我们先得了解一下.net framework平台的类的构造.在这个平台上有一个万物之源,那就是System.Object类型,在之下系统又分了值类型(Value Type )和引用类型(Reference Type).值类型包括原类型(Sbyte、Byte、Short、Ushort、Int、Uint、Long、Ulong、Char、Float、Double、Bool、Decimal)、枚举(enum)、结构(struct),引用类型包括:类、数组、接口、委托、字符串等。所以到这里我们就可以得出一个结论,文章开头提的那个问题的答案也就不言而喻了.我们自定义声明的类型是一种引用类型,所以我们把他放到object里面的时候,是不会发生装箱操作的.

 

具体操作:

下面我们来解析一下装箱和拆箱系统做了那些操作

前面我们已经说到.值类型数据是分配在栈(stack)中,他是一个先进后出的结构,由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.而引用类型数据分配在堆(heap)上,其操作方式类似于数据结构中的栈。堆他是一种顺序随意的结构,一般由程序员分配释放若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。具体在.net框架上的情况你可以阅读  .NET中栈和堆的比较 这篇文章,这位博主翻译了四篇关于这方面的文章,为中国的IT视野做出了巨大的贡献啊.

我们来结合一个小例子说明一下装箱操作:

int i = 123; object o = (object)i;

对值类型在堆中分配一个对象实例,并将该值复制到新的对象中。按三步进行。 
第一步:新分配堆内存(大小为值类型实例大小加上一个方法表指针和一个SyncBlockIndex)。 
第二步:将值类型的实例字段拷贝到新分配的内存中。 
第三步:返回堆中新分配对象的地址。这个地址就是一个指向对象的引用了。

IC97798

我们通过这种方式将一个值类型的int i装箱为一个object类型的 o变量

拆箱就是一个逆过程了.将一个object 类型的o变量还原为int型的i变量,它进行了如下操作:

(1)环境须先判断堆栈上指向合法对象的地址,以及在对此对象向指定的类型进行转换时是否合法,如果不合法,就抛出异常;

(2)当判断类型转换正确,就返回一个指向对象内的值的指针。

针对上面的合法性判断,有两点需要我们注意:

(1)包含已装箱的值类型的引用的变量如果为null,就抛出一个NullReferenceException异常。

(2)如果引用指向的对象不是所要求的值类型的一个已装箱的实例,就抛出一个InvaildCastException异常

 

 

带来的影响:

我们可以从两个方面考虑:一个就是对于堆的操作效率比较低;另一个就是对于堆上分配的内存资源,需要GC来回收,从而降低程序效率。

显然,直观的来说.装箱时,生成的是全新的引用对象,这会有时间损耗,也就是造成效率降低。 
当然我们也可以直观的看出,拆箱所带来的性能损失是远小于装箱所带来的损失的.

365据说看到好文章不转的人,服务器容易宕机
原创文章如转载,请注明:转载自郑州网建-前端开发 http://camnpr.com/
本文链接:http://camnpr.com/net-wiki/311.html