【C#】值传递、引用传递和string类型的不可变性
值类型和引用类型
值类型/引用类型包含有:
- 值类型:int、double、bool、char、decimal、struct、enum
- 引用类型:string、自定义类、数组、集合、object、接口
二者的区别:
1、值类型和引用类型在内存上存储的地方不同:
值类型存储在栈中,引用类型存储在堆中。
2、在传递值类型和传递引用类型时,传递方式不同;
值类型的传递
值类型在传递的时候,传递的是值本身。
1 | using System; |
运行结果:
内存图:
在执行 int b=a; 时,在栈中开辟一块空间用于存储b,并将a中的值传给b。执行完 b=2; 后,b被赋予了新值,并覆盖了原来的值。根据输出结果,值传递后,b的值与a的值无关,互不影响。
引用类型的传递
注意:这里引用传递的运行结果放在string类型上会有所不同,这是因为string类型具有不可变性,string类型的不可变性在下文会有介绍。
引用类型传递的时候,传递的是对这个对象的引用(即存在堆中的地址)。
下面以自定义类(Person)来说明:
1 | using System; |
运行结果:
内存图:
创建完成p1对象后,在堆上开辟一块存储空间,并将该存储空间的地址放在栈上,栈中这块空间的地址(标识)是p1。当p1对象传递给p2后,只是将对堆中的存储的引用(堆中的地址)复制一份传给p2,完成传递后p1和p2共同指向同一块内存,所以p1或p2中任意一个更改存储内容后,另一个也会改变。
string类型的不可变性
先按照上述“引用类型的传递”的思路来看string类型的传递:
1 | using System; |
运行结果:
从运行结果可以看出,string类型的传递和一般引用类型不同,这是因为string类型具有不可变性:
- 当给一个字符串重新赋值以后,旧值并没有销毁,而是重新开辟了一块空间用于存储新值。
内存图:
在a赋值“张三”并传递给b后,根据“引用类型的传递”,a和b共同指向“张三”(如图:堆地址为10001)这块内存。但是,在b重新被赋值为“李四”后,堆中开辟一块空间存储“李四”,旧值“张三”依然存在,新值的堆地址(如图:堆地址为10002)赋给栈中b的存储以使b指向“李四”。至此,a和b就不再指向同一块堆空间了。故运行结果与一般引用类型有所不同。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 谋仁 · Blog !
评论