大部分人都對引用類型熟悉,乃至精通,大家都知道對於一個類,聲明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";
這種技術才是駐留技術。