下面是FCL中值类型和引用类型的区别,用表格总结如下:
| 值类型 | 引用类型 |
内存分配 | 线程栈 | 托管堆 |
垃圾回收 | 不考虑 | 考虑 |
表示形式 | 未装箱和已装箱 | 总是已装箱 |
是否可以作为基类 | 不能作为基类,不能有虚方法 | 可以作为基类,也能有虚方法 |
初始化的值 | 0 | Null |
复制 | 逐字段复制(深拷贝) | 只复制内存地址(浅拷贝) |
操作时影响 | 只影响当前对象,不会影响另一个对象 | 这个引用所对应的所有对象 |
下面是一个实际的例子详细说明了值类型和引用类型在内存中的布局,代码如下:
namespace ValueTypeDemo1 { //值类型 struct SomeVal { public int x; } //引用类型 class SomeRef { public int x; } class Program { static void Main(string[] args) { SomeVal v1 = new SomeVal();//在线程栈上分配 SomeRef r1 = new SomeRef();//在托管堆上分配 v1.x = 5;//在栈上修改 r1.x = 5;//提取指针 Console.WriteLine(v1.x);//输出"5" Console.WriteLine(r1.x);//同样输出"5" SomeVal v2 = v1;//在栈上分配并深拷贝成员 SomeRef r2 = r1;//只复制引用(指针) v1.x = 9;//v1.x会更改,v2.x不会更改 r1.x = 8;//r1.x和r2.x都会更改 Console.WriteLine(v1.x);//输出"9" Console.WriteLine(v2.x);//输出"5" Console.WriteLine(r1.x);//输出"8" Console.WriteLine(r2.x);//输出"8" } } }
下面是程序在内存中的布局,如图所示: