C# 值类型和引用类型
C# 值类型和引用类型
内存中主要分为两块空间: 栈空间和堆空间。他们都是用来存储数据的。不同类型的数据存储在不同的地方。值类型和引用类型划分依据是他们在内存中存储的结构不同。
值类型
所有的数值类型(long int short byte decimal double float......)、char、bool、枚举、结构均为值类型
引用类型
string (是一个特殊的引用类型)、数组和类均为引用类型。
值类型和引用类型的区别
1、首先在Test命名空间下定义了一个ClassTest类和一个SturctTest的结构体,如下面代码所示:
1 namespace Test 2 { 3 /// <summary> 4 /// ClassTest 类 5 /// </summary> 6 public class ClassTest 7 { 8 //名字 9 public string Name; 10 } 11 12 /// <summary> 13 /// StructTest 结构体 14 /// </summary> 15 public struct StructTest 16 { 17 //名字 18 public string Name; 19 } 20 }
2、在程序的入口调用它们,如下面代码所示:
View Code
1 namespace Test 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //创建 ClassTest 对象,并为对象中的Name字段赋值 8 ClassTest c1 = new ClassTest(); 9 c1.Name = "我是c1"; 10 11 //创建 StructTest 对象,并为对象中的Name字段赋值 12 StructTest s1 = new StructTest(); 13 s1.Name = "我是s1"; 14 } 15 } 16 }
我们来看看这时候这两个对象在内存空间中是如何存在的:

从这张图可以看出:
1、类实例化出来的对象,真实的值是存储在堆空间中的,栈空间中的变量存储的只是这个对象在堆空间中的一个引用地址。
2、结构实例化出来的对象,真实的值是直接存储在栈空间中的变量中。
3、接下来我们在上面代码的基础上加几行代码:
首先定义一个ClassTest类型的变量c2,并将c1的值赋给该变量,再改变c2的Name字段的值。再定义一个StructTest类型的变量s2,并将s1的值赋给该变量,再改变s2的Name字段的值。
1 namespace Test 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //创建 ClassTest 对象,并为对象中的Name字段赋值 8 ClassTest c1 = new ClassTest(); 9 c1.Name = "我是c1"; 10 //新加代码 11 ClassTest c2 = c1; 12 c2.Name = "我是c2"; 13 Console.WriteLine("c1的Name为:{0},c2的Name为:{1};", c1.Name, c2.Name);//结果:第一个值为:我是c2,第二个值为:我是c2 14 15 16 //创建 StructTest 对象,并为对象中的Name字段赋值 17 StructTest s1 = new StructTest(); 18 s1.Name = "我是s1"; 19 //新加代码 20 StructTest s2 = s1; 21 s2.Name = "我是s2"; 22 Console.WriteLine("s1的Name为:{0},s2的Name为:{1};", s1.Name, s2.Name);//结果:第一个值为:我是s1,第二个值为:我是s2 23 } 24 } 25 }
从最终结果来看,对类和结构做同样的操作,最终的值的结果不一样。这是为什么呢?我们来看下加了代码之后,变量在内存中的变化情况,如下图:

根据图可以看出,因为类是引用类型,所以将c1变量赋值给c2变量,其实只是把存在变量中的引用地址赋值给了c2变量,这时候c2和c1指向堆空间中同一个对象,修改c2的值,c1的值也会受影响。而结构是值类型,因为变量的值本身是存在该变量上,将s1变量赋值给s2变量,是拷贝了一份出来赋给s2变量,这时候修改s2变量的值是不会影响s1变量的值。
所以无论是值类型还是引用类型的变量之间相互赋值,都是将源变量中的值拷贝一份,将这个副本赋值给目标变量。而区别在于
- 值类型:因为值类型的变量中存储的是真实的值,所以拷贝传递的也是真实的值。赋值完成以后,对一个变量的修改不会影响另外的1个变量的值。
- 引用类型:因为引用类型的变量中存储的是对象的地址,所以拷贝传递的也是地址。赋值完毕以后,两个变量指向了同一个对象。对1个变量进行修改对另外的变量有影响。
局部变量及成员变量
局部变量:
相同点: 无论局部变量是值类型的还是引用类型的,那么这个局部变量始终是开辟在栈空间中的.
不同点: 值类型变量的真实的值,直接存储在栈空间中的变量中.
引用类型的变量,对象是存储在堆空间中的,栈空间中的变量中存储的是对象在堆空间中的地址.
成员变量:
成员变量除于对象。无论这个成员变量是值类型的还是引用类型,都跟着对象一起开辟在堆空间中。这个成员变量存储值的原理和局部变量一样。

浙公网安备 33010602011771号