了解.NET的类型很重要
.NET的主要类型分为值类型和引用类型
区分这2种类型
1、内存方面
值类型:
包括枚举enum 和结构 struct
内存分配:
实例通常分配在线程的堆栈上,并且不包括任何指向实例数据的指针,因为变量本身就包含了其实例数据,内存不由GC来控制,作用域结束时,值类型会自行释放
引用类型:
包括类,接口,数组,委托
内存分配:
实例分配在托管堆上,保存了实例数据的内存引用,由GC(Garbage Collection)来控制其回收
特殊情况:
出现嵌套的时候,即值类型嵌套引用类型,引用类型嵌套值类型,那么内存又是如何分配的呢?
值类型实例总是分配在他声明的地方,引用类型实例总是分配在托管堆上
2、sizeof()运算符用于获取值类型的大小,但是不适用于引用类型
3、值类型使用new操作符或者赋初值完成初始化,而单纯的定义没有完成初始化,此时对成员的引用将不能通过编译
4、引用类型在性能上欠于值类型
5、值类型继承自System.ValueType ,而System.ValueType 又继承自 System.Object
6、值类型是密闭的,不能作为其他类型的基类,但是可以单继承或者多继承接口,而引用类型一般有继承性
7、值类型没有多态,但是引用类型有多态
值类型和引用类型的互相转换
装箱和拆箱
按值传递和按引用传递:
按值传递
不管是引用类型按值传递还是值类型按值传递,都是在堆栈上复制一个对象的实例,将这个新的实例去传递,不改变原有实例的值。
按引用传递
是直接将指向实例的引用地址进行传递,改变了地址,则会改变参数的值
传递的是参数的地址
值类型按引用传递时实现的是对值类型参数实例的直接操作
Ref和Out均为引用传递,区别 是Ref参数传递前该参数必须已经被初始化,而out参数传递不需要
用户自定义类型转换的实现方式:
Static 访问修饰操作符 转换修饰操作符 operator 类型 (参数列表)
所有的转换都必须是static 见P160
如果声明了一个类对象指向一个托管堆地址,但是该类对象改变了引用,那么之前的地址会被GC回收
装箱和拆箱
装箱
将值类型数据转换成无类型的引用对象
过程:
1、 内存分配
2、 实例拷贝
3、 地址返回(不包含这步,但是常常伴随着一起发生)
拆箱
获取已装箱对象中来自值类型部分字段的地址,在执行上不包括字段的拷贝过程
过程:
1、 实例检查
2、 指针返回
3、 字段拷贝
遵循的规范:
1、 拆箱后必须保证执行后的结果是原来未装箱时的类型
2、 引用类型一直保持着装箱状态,装箱和拆箱是针对值类型而言的
应该尽量避免装箱拆箱的发生,可以考虑使用泛型
ArrayList,HashTable,Emun均易引起装箱