C#中的两种类型
- 值类型:顾名思义,就是用于存放值的数据类型
- 引用类型:比值类型多一道程序,他并没有直接存储这个数据,而是存储了这个数据的地址,地址再指向这个变量
从字面意义上来看,值类型直接存储其值,引用类型存储这个值的一个引用。这两种不同的数据类型存储在内存的不同位置,值类型存储在堆栈中;引用类型存储在托管堆上。首先看看下面的一个例子,他们是两种不同的类型,存储在内存的不同位置。
int
i
=
10
;// 值类型
int
j
=
i
; // 引用类型,他指向i的地址,i从地址中找到值,并告诉给j
引用类型变量并不包含类型的实例,而是对实例的引用。由于值类型是存储在堆栈中的,因此它的处理速度和效率比较高,值类型的作用域结束后就会被自动释放 ,节省内存;相反,使用托管堆的引用类型效率会低得多,但是比较灵活,它需要CG机制来进行垃圾回收 。程序员在进行程序设计的时候往往要考虑不能过多的使用引用类型变量,因为这会消耗大量内存,使得程序的执行效率下降,这就是为什么当我们对一个字符串有很多操作时要使用StringBuilder类的实例,而不是直接定义一个String类型的变量。
注意,String类型也是引用类型,当我们修改一个String类型变量时,实际上并没有修改它的值,而是在内存中创建了一个全新 的String对象。这也是为什么之前所说的大量使用和修改字符串会造成内存利用太多的问题。我们看下面的示例。
string
s1
=
"Sam"
;
string
s2
=
s1
;
Console
.
WriteLine
("s1 is "
+
s1
);
Console
.
WriteLine
("s2 is "
+
s2
);
s1
=
"Bob"
;
Console
.
WriteLine
("s1 is "
+
s1
);
Console
.
WriteLine
("s2 is "
+
s2
);
输出结果:
s1 is Sam
s2 is Sam
s1 is Bob
s2 is Sam
注:因为修改的s1实际上是创建了另一个字符串对象,s1又重新指向了这个新创建对象的地址,所以表面上看起来是变了,实际上之前的实例是没有改变的。同样,s2的引用没有改变,因此我们看到的还是之前的值。
下图是值类型和引用类型得类型和描述