在了解装箱与拆箱之前,首先了解一下两种数据类型:值类型和引用类型。
一、值类型
值类型就是一个包含实际数据的量。当定义一个值类型的变量时,C#会根据它所声明的类型,以堆栈方式分配一块大小相适应的存储区域给这个变量,对这个变量的读、写操作就直接在这块内存区域进行。
例如:
int INum=10;//分配一个32位内存区域给变量INum,并将10放入该内存区域
注意:
1、值类型是在柞中分配内存,在声明时初始化才能使用,不能为null。
2、值类型超出作用范围系统自动释放内存
3、主要由两类组成:结构、枚举(enum),结构分为:
a、整型(Sbyte、Byte、Char、Short?Ushort、Int、Unit、Long、Ulong)
b、浮点型(Float、Double)
c、decimal
d、bool
e、用户定义的结构(struct)
二、引用类型
引用类型的变量不存储它们所代表的实际数据,而是存储实际数据的引用。引用类型分两步创建:首先在堆栈上创建一个引用变量,然后在堆上上创建对象本身,再把这个内存的句柄(也是内存的首地址)赋给引用变量。
例如:
string s1,s2; s1="a";s2=s1;
其中s1,s2是指向字符串的引用变量,s1的值是字符串“a”存放在内存的地址,这就是字符串的引用,两个引用变量之间的赋值,使s1、s2都是对“a”的引用。
注意:
1、引用类型在堆中分配内存,初始化时默认为null
2、引用类型通过垃圾回收机制进行回收
3、包括类、接口、委托、数组及内置引用类型object与string,其中object和string是两个比较特殊的类型。C#中,所有类型都是直接或间接从object继承的。可以将任何类型的值赋给object类型的变量。
4、堆和栈是两个不同的概念,在内存中存储位置也不同,堆一般用于存储可变长度的数据,按任意顺序和大小进行分配和释放内存,而栈一般一般用于存储固定长度的数据,按先后进出的原则存储数据项的一种数据结构。
三、装箱与拆箱
值类型和引用类型之间的转换被称为装箱与拆箱。通过这个操作可以轻松实现值类型和引用类型的相互转换,任何类型的值最终都可以按照对象来处理。
1、装箱
装箱是值类型转换为object类型,或者转换为由值类型所实现的任何接口类型。把一个值类型装箱就是创建一个对象并把值赋给对象。
例如:
int i=123; //把“123“赋给int型变量 object o=i; //装箱操作
2、拆箱
拆箱是从object类型到值类型或从接口类型到实现该接口的类型的显示转换。取消装箱的步骤为:
(1)检查对象实例是否是给定的值类型的装箱值。(拆箱后没有转换成原类型,编译时不会出错,但运行会出错,所以一定要确保这一点。用GetType().ToString()判断时一定要使用类型全称,如:System.String而不要String)
(2)将该值从实例复制到值类型变量中
int i=123; //把”123“赋给int型变量i objecto=i; //装箱操作 int j=(int)o //拆箱操作
由于拆箱的过程中要对引用类型内存放的值进行检查,因此对于不兼容的类型转换将导致异常。例如:
int i=1; //把”1“赋给int型变量; object obj=i; // 装箱操作 string j=(string) obj; //类型不兼容
注意:当一个"装箱"操作把值类型转换为引用类型时,不需要显示地强制类型转换,而拆箱操作就把引用类型转换到值类型时,由于它可以强制转换到任何可以相兼容的值类型,所以必须显示地强制类型转换。