【前置知识】
内存中有栈区(stack)和堆区(heap)来存放数据。对值类型和引用类型的区别这个问题而言,我们只需要明白以下两点即可:
- 在空间大小上,栈<堆
- 在读取速度大小上,栈>堆
【拓展】内存中的堆和栈到底是什么
【定义】
按照数据在内存中的存储位置,可以将所有数据分为值类型和引用类型两类。
有类数据的规模(即数据量)很小,所以需要的空间也小,其通常存储在栈区,也即栈区存储了这类数据的值,这类数据就叫值类型数据。我们要获取值类型数据的值,只要找到其在栈区中的哪个位置(即地址)即可获得该值。
有类数据的规模(即数据量)很大,所以需要的空间也大,其通常存储在堆区,也即堆区存储了这类数据的值,而在栈区存储了这类数据的引用,这类数据就叫引用类型数据。我们想要获取引用类型数据的值,要先找到数据的引用在栈区的位置,在这个位置获取引用,通过引用找到数据在堆区的位置,获得数据的值。
【C#中预定义的值类型和引用类型】
【前置知识】对数据类型的理解
C#中预定义的值类型数据包括:整型、浮点型、字符型、bool型
C#中预定义的引用类型数据包括:string型、object型(注解:通常而言,字符串可以很长,需要的空间较大,而一般的数需要的空间不大)
C#中的值类型包括:值类型数据、结构struct、枚举enum
C#中的引用类型包括:引用类型数据、数组、类、接口、委托(注解:数组、类可以看做由很多的数据组成的,需要的空间大)
【值类型和引用类型的区别】
【赋值区别】
值类型:把数据的值复制过去
引用类型:把数据的引用复制过去
【内存分配区别】
值类型:只需要栈中单独的一块内存区域用于存储数据的值。
引用类型:需要堆中的一块区域存放数据的值,还需要栈中的一块内存区域存放数据的引用(即地址)
【继承区别】
值类型:继承自System.ValueType,所有的不能被继承
引用类型:继承自Sysyem.Object,有的可以被继承(主要指类和接口)
class Program
{
static void Main(string[] args)
{
int a = 0;
int b = 1;
a = b;//把b的值复制给a
a = 2;
Console.WriteLine(a+" "+b);//输出2 1
string str1 = "abc";
string str2 = "xyz";
str1 = str2;//把str2的引用复制给str1
str1 = "lmn";//在堆中新分配了一块区域存储“lmn”(而不是将str2所指的存储区域的值更改),并把引用给str1,
Console.WriteLine(str1 + " " +str2);//输出lmn xyz
int[] A = {1, 2, 3};
int[] B = {4, 5, 6};
A = B;
A[0] = 10;//更改了引用所指向的存储区域中的一个数的数值
foreach (int temp in A)
{
Console.Write(temp + " ");//输出10 5 6
}
foreach (int temp in B)
{
Console.Write(temp + " ");//输出10 5 6,而不是4 5 6
}
Console.ReadKey();
}
}
【值类型和引用类型之间的类型转换】
【参考】
[1]《C#本质论5.0》
[2]https://blog.csdn.net/qiaoquan3/article/details/51202926