C#数据类型分为两大类:值类型(数据存放在栈stack中)和引用类型(数据存放在堆heap中,地址存放在栈stack中)。下图是列举了两种数据类型的数
值类型变量声明后,不管是否已经赋值,编译器为其分配内存。声明一个引用类时,
只在栈中分配内存,用于存放地址,而并没有为其分配堆上的内存空间。
值类型与引用类型使用区别:
本部分主要以自己编写程序来体验两者区别。
对象的传递:
输出结果:
将值类型的变量赋值给另一个变量,会执行一次赋值,赋值变量包含的值;
将引用类型的变量赋值给另一个引用类型变量,它复制的是引用对象的内存地址,在赋值后就会多个变量指向同一个引用对象实例。
参数按值传递:
输出结果:
对于值类型(stu1),传递的是该值类型实例的一个副本,因此原本的值stu1并没有改变;
对于引用类型(Student stu2),传递是变量stu2的引用地址(即stu2对象实例的内存地址)拷贝副本,因此他们操作都是同一个stu2对象实例。
参数按引用传递:
输出结果:
不管是值类型还是引用类型,可以使用ref或out关键字来实现参数的按引用传递。ref或out关键字告诉编译器,方法传递的是参数地址,而非参数本身。
在按引用传递时,方法的定义和调用都必须显式的使用ref或out关键字,不可以省略,否则会引起编译错误
注:string与一般引用类型有区别。以下是我对string与其他引用类型进行比较,发现的不同,所编写的程序代码
String:
显示结果:
数组:
显示结果:
结论:
在string字符串,一开始s1地址指向是hello world,因为s2=s1,所以s2地址也同样指向hello world。
当s1再次赋值hello Yeebo时,堆中就会开辟出数据hello Yeebo,而且hello world没有消失,没有被覆盖。s1地址就指向hello Yeebo,s2地址还是原来的hello world。
在引用类型数组上,一开始s1和s2的地址都指向{1,2,3}
当给S1进行数据更改时,由于是引用类型,所以在{1,2,3}上面进行更改,就会对S2进行覆盖
装箱和拆箱:
装箱和拆箱是值类型和引用类型之间的相互转换。
装箱是值类型向引用类型转换时发生的,拆箱是引用类型向值类型转换时发生的。
装箱是隐式的,拆箱是显式的。如下图代码。
结果:
注:对于拆箱存在单词或汉字等转换为int的,这个过程是可能会报错的, Convert.ToInt32()是不可行的,如下图。
结果:
需要使用int.TryParse(),才不报错,如下图。
结果:
个人总结:
值类型有更好的效率,但不支持多态,适合用作存储数据的载体。而引用类型支持多态,适合用于定义程序的行为。
引用类型可以派生新的类型,而值类型不能。