第二个ReferenceEquals调用返回false。为什么s4中的字符串没有内嵌?(我并不关心StringBuilder相对于字符串连接的优势。)
string s1 = "tom";
string s2 = "tom";
Console.Write(object.ReferenceEquals(s2, s1)); //true
string s3 = "tom";
string s4 = "to";
s4 += "m";
Console.Write(object.ReferenceEquals(s3, s4)); //false当我执行String.Intern(s4);时,我仍然得到false。
这里,s3和s4都被限制了,但是它们的引用不相等吗?
string s3 = "tom";
string s4 = "to";
s4 += "m";
String.Intern(s4);
Console.WriteLine(s3 == s4); //true
Console.WriteLine(object.ReferenceEquals(s3, s4)); //false
Console.WriteLine(string.IsInterned(s3) != null); //true (s3 is interned)
Console.WriteLine(string.IsInterned(s4) != null); //true (s4 is interned)发布于 2010-04-25 07:44:27
s4中的字符串被截获。但是,当您执行s4 += "m";时,您已经创建了一个不会被实例化的新字符串,因为它的值不是字符串文字,而是字符串连接操作的结果。因此,s3和s4是位于两个不同内存位置的两个不同的string实例。
有关字符串内嵌的更多信息,请查看here,特别是最后一个示例。当您执行String.Intern(s4)时,您实际上是在实例化字符串,但是您仍然没有在这两个实例化字符串之间执行引用相等测试。String.Intern方法返回内部字符串,因此您需要执行以下操作:
string s1 = "tom";
string s2 = "tom";
Console.Write(object.ReferenceEquals(s2, s1)); //true
string s3 = "tom";
string s4 = "to";
s4 += "m";
Console.Write(object.ReferenceEquals(s3, s4)); //false
string s5 = String.Intern(s4);
Console.Write(object.ReferenceEquals(s3, s5)); //true发布于 2010-04-25 07:43:31
字符串是不可变的。这意味着它们的内容不能被改变。
在内部执行s4 += "m";时,CLR会将字符串复制到内存中包含原始字符串和附加部分的另一个位置。
参见MSDN string reference。
发布于 2010-04-25 08:16:22
首先,到目前为止关于不可变字符串的所有内容都是正确的。但是有一些重要的东西没有写出来。代码
string s1 = "tom";
string s2 = "tom";
Console.Write(object.ReferenceEquals(s2, s1)); //true显示真正的"True",但仅仅是因为一些小的编译器优化,或者像这里这样,因为CLR忽略了C#编译器属性(参见“通过C#的CLR”一书),只将一个字符串"tom"放在堆中。
其次,您可以使用以下几行代码来修复这种情况:
s3 = String.Intern(s3);
s4 = String.Intern(s4);
Console.Write (object.ReferenceEquals (s3, s4)); //true函数String.Intern计算字符串的散列代码,并在内部散列表中搜索相同的散列。因为它找到了它,所以它返回对已经存在的String对象的引用。如果该字符串不存在于内部哈希表中,则会复制该字符串并计算哈希值。垃圾收集器不会为字符串释放内存,因为它被哈希表引用。
https://stackoverflow.com/questions/2706607
复制相似问题