认识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";

这种技术才是驻留技术。

posted @ 2011-12-28 10:23  Anleb  阅读(4006)  评论(53编辑  收藏  举报