从C#中的引用类型到String
来源:互联网 发布:淘宝助理有什么作用 编辑:程序博客网 时间:2024/06/05 10:03
最近面试被问到一个问题,在C#里面String是值类型还是引用类型,当时想都没想就说是引用类型。后来面试官又接着问为啥,我就给愣住了,随口说了个可以为Null就不会了。下来仔细想了想这个问题。
首先,要说明string为什么是引用类型,先来考虑下什么是引用类型,什么是值类型,以及他们的区别是什么。在网上随便搜搜基本上的解释都是,值类型存储在栈上,引用类型存储在堆上。这句话基本上说明不了什么。
在仔细想想,为什么当初设计C#语言的时候要分为值类型和引用类型呢。全都搞成一样不是更简单么。可能就是因为在c#里面取消了c++里的指针,而通过引用类型可以实现之前指针可以实现的功能。(不太懂指针,所以就不多说了)我能想到的区别就是在函数传参的时候,比如我有一个函数
void main(int b) { b = 1; b++; int c = 101; b = c; }
我在调用他时传了一个参数a , 可以这样写
int a = 100;main(a);
结果就是运行完这个函数后,a的值不会改变,那么其实我是把a的值(比如说100)给了函数,然后函数里面可以用这个值进行计算之类的,不管函数里面怎么变都不会改变a本身,这也就是函数传参时的形参和实参的区别,不管参数是什么类型的(值类型或者引用类型),在给一个函数传参的时候都是把实参(比如上面的a)的值取出来赋给形参(b),形参其实就是一个局部变量,在函数被调用时创建,在函数运行完后销毁。但如果有一天我写了一个程序
int a = 100;a = 10;Console.Write(a);我想把a=10;这句写在一个函数里,方便以后重复调用(是不是有点多此一举....),如果按照上面的写法肯定是不行的,因为函数里的形参的改变是不会影响外面的a。在c++里面好像可以用取地址符(&)传参实现。但是标准的c#里面没有这个东西了,怎么办呢。这个时候就要用到引用类型了。可以这么写把我想要改变的变量封装到一个类里面。
class A { public int a1 = 0; public int a2 = 0; public int a3 = 0; } static void Main(string[] args) { A a = new A(); a.a1 = 1; a.a2 = 2; a.a3 = 3; Console.WriteLine(a.a1 + " " + a.a2 + " " + a.a3); main(a); Console.WriteLine(a.a1 + " " + a.a2 + " " + a.a3); Console.ReadLine(); } static void main(A b) { b.a1 = 10; b.a2 = 100; b.a3 = 200; }所有的类都是引用类型的。在传参的时候虽然也是通过复制值传递,但是由于引用类型里面存的其实是一个地址,所以传递值的时候其实也是传递的地址值,但在实际操作的时候会根据地址找的具体的值(a1,a2,a3)的位置然后操作。在内存里过程如图:
上面代码里首先实例化一个对象a,a的具体值(a1,a2,a3)会存在堆里(假设地址是0001),然后在栈里的一个位置存下这个地址0001,a就是指向栈里的这个位置。当把a当参数传给函数时,函数会实例化一个形参b(在栈里,并没有在堆里分配新的空间)然后将a的值(0001)复制给b。由于传的值是一个地址0001,所以在实际操作b的时候就是操作堆里0001位置的值。也就相当于操作了a的值。
其实在函数传参的时候还有引用传递的情况,运用关键字ref和out。
但这些都是书上说的理论,感觉总有点不真实,于是写一段代码验证下:
class A { public int a1 = 0; public int a2 = 0; public int a3 = 0; } static A a = new A(); static int aa ; static void Main(string[] args) { a.a1 = 1; a.a2 = 2; a.a3 = 3; aa = 11; Console.WriteLine(a.a1 + " " + a.a2 + " " + a.a3); main(a,aa); Console.WriteLine(a.a1 + " " + a.a2 + " " + a.a3); Console.ReadLine(); } static void main(A b,int bb) { <strong>Console.WriteLine ( Object.ReferenceEquals(b, a)); Console.WriteLine ( Object.ReferenceEquals(bb, aa));</strong> b.a1 = 10; b.a2 = 100; b.a3 = 200; }运行的结果是:
Object.ReferenceEquals方法用来判断两个对象是不是引用同一个东西。
可以看到值类型A在函数传参以后指向的还是以前的对象,而值类型int则不是。
然后再试试string类型
static string str; static void Main(string[] args) { str = "aaa"; main(str); Console.ReadLine(); } static void main(string a) { Console.WriteLine ( Object.ReferenceEquals(a, str)); }结果果然还是true,看来string确定是引用类型无疑了。
关于string类型还有一些很神奇的,比如string类型的值是readonly的,如果要改变一个string对象的值,那么其实是新建了一个string对象。
string str = "aaa"; string str1 = str; Console.WriteLine(Object.ReferenceEquals(str1, str)); str1 = "aaaa"; Console.WriteLine(Object.ReferenceEquals(str1, str)); Console.ReadLine();结果是true 和false 所以在频繁改变字符串值的时候还是用stringbuilder比较好。
还有一点比较神奇的是,CLR会自动给string类型建立一张记录表,每当新初始化一个string对象时,先查记录表,如果已经存在相同的字符串,则直接指向它的位置,这样就不用再次分配空间了。例如
string str = "aaa"; string str1 = "aaa"; Console.WriteLine(Object.ReferenceEquals(str1, str));这样的代码结果也是true,str和str1其实是指向堆里面的同一个位置。
- 从C#中的引用类型到String
- C#中的引用类型
- C# string 特殊引用类型
- 详解C#引用类型String
- c#中的string类型
- C# 值类型和引用类型--string
- C# string类型(引用类型)
- 【引用】C#中的类型转换
- C++ : 从栈和堆来理解C#中的值类型和引用类型
- C# 特殊的引用类型string
- C# string 特殊的引用类型
- 理解C#中的string类型
- 理解C#中的string类型
- 理解C#中的string类型
- 理解C#中的string类型
- C#中的String类型转换
- c#中从string到string[]
- C#中的值类型和引用类型
- IOS开发:XMPP聊天工具的使用
- Easyui动态加载后台数据的例子
- 错误 1 error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
- 程序员,你敢休息一下吗?——真爱生命,远离编程
- 黑马程序员——基础知识-反射机制
- 从C#中的引用类型到String
- LeetCode---Find Minimum in Rotated Sorted Array
- HttpClient及有关jar包详解
- 代码没报错 工程出现错误
- 电视行业再爆猛料:TCL明天将开启巅峰科技大战
- 1036. 跟奥巴马一起编程(15)
- C++通讯录程序
- phpstudy安装过程遇到的错误
- BaseAdapter2.0 -----ViewHolder