关于字符串的驻留的机制, 对于那些了解它的人肯定会认为很简单, 但是我相信会有很大一部分人对它存在迷惑. 在开始关于字符串的驻留之前, 先给出一个有趣的 Sample:
- Code Snip:
- static void Main(string[] args)
- {
- string str1 = "ABCD1234";
- string str2 = "ABCD1234";
- string str3 = "ABCD";
- string str4 = "1234";
- string str5 = "ABCD" + "1234";
- string str6 = "ABCD" + str4;
- string str7 = str3 + str4;
- Console.WriteLine("string str1 ="ABCD1234";");
- Console.WriteLine("string str2 ="ABCD1234";");
- Console.WriteLine("string str3 ="ABCD";");
- Console.WriteLine("string str4 ="1234";");
- Console.WriteLine("string str5 ="ABCD"+"1234";");
- Console.WriteLine("string str6 ="ABCD"+ str4;");
- Console.WriteLine("string str7 = str3 + str4;");
- Console.WriteLine("object.ReferenceEquals(str1, str2) = {0}", object.ReferenceEquals(str1, str2));
- Console.WriteLine("object.ReferenceEquals(str1,"ABCD1234") = {0}", object.ReferenceEquals(str1, "ABCD1234"));
- Console.WriteLine("object.ReferenceEquals(str1, str5) = {0}", object.ReferenceEquals(str1, str5));
- Console.WriteLine("object.ReferenceEquals(str1, str6) = {0}", object.ReferenceEquals(str1, str6));
- Console.WriteLine("object.ReferenceEquals(str1, str7) = {0}", object.ReferenceEquals(str1, str7));
- Console.WriteLine("object.ReferenceEquals(str1, string.Intern(str6)) = {0}", object.ReferenceEquals(str1, string.Intern(str6)));
- Console.WriteLine("object.ReferenceEquals(str1, string.Intern(str7)) = {0}", object.ReferenceEquals(str1, string.Intern(str7)));
- }
下边是输出的结果:
接下来我们来逐句地分析这段代码:
首先我们创建了两个完全相同的字符串(ABCD1234), 并将他们分别赋予了两个字符创变量 --str1 和 str2. 然后把它们传给了 object.ReferenceEquals. 我们知道 object.ReferenceEquals 是用于确定两个变量是否具有相同的引用 -- 换句话说, 当两个变量引用的是同一块托管推的内存快的时候, 返回 True, 否则返回 False.
- string str1 = "ABCD1234";
- string str2 = "ABCD1234";
- object.ReferenceEquals(str1, str2)= True;
- object.ReferenceEquals(str1, "ABCD1234")) = True;
令我们感到奇怪的是, 当我们分别创建的引用类型两个变量 --string 是引用类型. 照理说 CLR 会在托管堆 (Managed Heap) 中为它们分配两段内存快, 他们不可能具有相同的引用才对, 但是为什么 object.ReferenceEquals 方法会返回 True 呢. 而对于第二个比较 -- 一个字符串变量和一个和他具有相同内容的字符串 ("ABCD1234";) 直接进行比较, 按照我们对 CLR 内存的分配的一般理解, 应该是 CLR 首先会在托管堆中为这段字符串 ("ABCD1234") 分配内存快, 然后把相对应的引用传递给 object.ReferenceEquals 方法(由于分配在托管堆的这段字符串并没有被任何变量引用, 所以当垃圾回收的时候会被回收掉), 所以无论如何也不应该返回 True.
我们先把问题留到最后, 接着分析我们的 Sample. 上面们对字符串变量之间以及变量与字符串之间进行了比较, 如果我们对一个字符串变量和一个动态创建的字符串 (通过 + Operator 把两个字符串连接起来) 进行比较, 结果又会如何呢? 我们来看看下面的伪代码演示:
- string str3 = "ABCD";
- string str4 = "1234";
- string str5 = "ABCD" + "1234";
- string str6 = "ABCD" + str4;
- string str7 = str3 + str4;
- object.ReferenceEquals(str1, str5) = True
- object.ReferenceEquals(str1, str6) = False
- object.ReferenceEquals(str1, str7)) = False
在上面的例子中, 我们用三种不同的方式创建了 3 个字符串变量 (str5,str6,str7)--string+string;string+variable;variable+variable. 然后分别和我们已经创建的, 和它们具有相同字符串 "值" 的变量(str1) 作比较. 同样令我们感到奇怪的是第一个返回 True, 而后两个则为 False. 带着这些疑惑我们来看看对于 string 这一特殊的类型说采用的特殊的