认识string的深度到底 有多深?(值类型与引用类型的Equals到底 差在哪?)
大部分人都对引用类型熟悉,乃至精通,大家都知道对于一个类,声明2个引用对象的变量,那么这2个变量的Equals,如果是引用了相同的对象那么可能是true,如果引用了不同的对象必然是False:
第一题:
Test one = new Test();
Test two = new Test();
Console.WriteLine("one == NUll:{0}", one == null);//false
Console.WriteLine(one.Equals(two));//false
Console.WriteLine(Test.Equals(one, two));//fase
Console.WriteLine(Test.ReferenceEquals(one, two));//false
对,或许你答对了,这就是我们的理论没错。
但是,请大家看下面的列子:
第二题:
Test one = new Test();
Test two = one;
Console.WriteLine(one.Equals(two));//true
Console.WriteLine(Test.Equals(one, two));//true
Console.WriteLine(Test.ReferenceEquals(one, two));//true
可能你的答案又对了,因为咱们知道对于一个引用变量赋值给一个新的引用变量,就是把引用该对象的内存地址赋值给了新引用变量,也就是把 指向对象的指针传递给了新引用变量。
这里:大家都知道,one two 2个引用变量 对象的对象是同一个对象,那么只要one 修改对象,那么two对应的对象也会改变。(two修改对象One也会改变)
如果以上都看懂了,你可以进入下一题:
第三题:
string s1 = "123";
string s2 = s1;
Console.WriteLine(s1.Equals(s2));//true
Console.WriteLine(string.Equals(s1, s2));//true
Console.WriteLine(string.ReferenceEquals(s1, s2));//true
上面这题???你答对了吗?
分析:
1.string是类,s1 s2是变量,储存在堆栈上(和值类型一样),在堆上建立2块内存新建2个对象(对象在堆上),应该说Equals的结果是False,为何true?
答案如下:
[引用 徐洪强博客]:
"CLR使用了一种叫字符串驻留的技术,对于
string str1="abc";
string str2="abc";
当CLR初始化时,会创建一个内部的散列表,其中的键为字符串,值为指向托管堆中字符串的引用。刚开始,散列表为空,JIT编译器编译方法时,会在散列表
中查找每一个文本常量字符串,首先会查找"abc"字符串,并且因为没有找到,编译器会在托管堆中构造一个新的指向"abc"的String对象引用,然
后将"abc"字符串和指向该对象的引用添加到散列表中。
接着,在散列表中查找第二个"abc",这一次由于找到了该字符串,所以编译器不会执行任何操作,代码中再没有其它的文本常量字符串,编译器的任务完
成,代码开始执行。执行时,CLR发现第一个语句需要一个"abc"字符串引用,于是,CLR会在内部的散列表中查找"abc",并且会找到,这样指向先
前创建的String对象的引用就被保存在变量s1中,执行第二条语句时,CLR会再一次在散列表中查找"abc",并且仍然会找到,指向同一个
String对象的引用会被保存在变量s2中,到此s1和s2指向了同一个引用,所以System.Object.Equals(s1,s2)就会返回
true了。"
好了进入下一题
//引用类型
string s1 = "123";
string s2 = s1;
s1 = "123456";//新建一个对象
Console.WriteLine(s2);//输出结果是:123
总结下经过3天的激烈讨论:
问题集中在 最后一题
当s2=s1的时候,只是s1 s2的指针都指向了“123”,当s1="123456"的时候新建了堆里的对象,那么s1的指针改变了,s2却为改变。
针对:
"CLR使用了一种叫字符串驻留的技术,对于
string str1="abc";
string str2="abc";
这种技术才是驻留技术。