字符串实习?
第二个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);
,我仍然是假的。
在这里,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)
s4
的字符串是实习的。 但是,当你执行s4 += "m";
,您创建了一个不会被实习的新字符串,因为它的值不是字符串文字,而是字符串连接操作的结果。 结果, s3
和s4
是两个不同存储器位置中的两个不同的字符串实例。
有关字符串实习的更多信息,请查看此处 ,特别是在最后一个示例中。 当您执行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
字符串是不可变的。 这意味着他们的内容无法更改。
当你做s4 += "m";
在内部,CLR将字符串复制到内存中的另一个位置,该位置包含原始字符串和附加部分。
请参阅MSDN字符串参考 。
首先,到目前为止所写的关于不可变字符串的所有内容都是正确的。 但是有一些重要的事情没有写出来。 代码
string s1 = "tom"; string s2 = "tom"; Console.Write(object.ReferenceEquals(s2, s1)); //true
显示真的“真”,但只是因为一些小的编译器优化或像这里因为CLR忽略C#编译器属性(参见“CLR via C#”一书)并且只在堆中放置一个字符串"tom"
。
其次,你可以用以下几行来解决这个问题:
s3 = String.Intern(s3); s4 = String.Intern(s4); Console.Write (object.ReferenceEquals (s3, s4)); //true
函数String.Intern
计算字符串的哈希码,并在内部哈希表中搜索相同的哈希值。 因为它找到了这个,所以它返回对已经存在的String
对象的引用。 如果内部哈希表中不存在该字符串,则会生成该字符串的副本并计算哈希值。 垃圾收集器不会释放字符串的内存,因为它由哈希表引用。
在C#中,每个字符串都是一个不同的对象,无法编辑。 您正在创建对它们的引用,但每个字符串都是不同的。 行为一致且易于理解。
我可以建议检查StringBuilder
类来操作字符串而不创建新实例吗? 对于你想要用字符串做的任何事情都应该足够了。
资料来源: https : //blogs.msdn.microsoft.com/ericlippert/2009/09/28/string-interning-and-string-empty/
字符串实习是编译器的一种优化技术。 如果在一个编译单元中有两个相同的字符串文字,则生成的代码可确保在程序集中只为该文字的所有实例(用双引号括起来的字符)创建一个字符串对象。
我来自C#背景,所以我可以通过举例说明:
object obj = "Int32"; string str1 = "Int32"; string str2 = typeof(int).Name;
以下比较的输出:
Console.WriteLine(obj == str1); // true Console.WriteLine(str1 == str2); // true Console.WriteLine(obj == str2); // false !?
注1 :通过引用比较对象。
注意2 :typeof(int).Name由reflection方法计算,因此在编译时不会对其进行求值。 这些比较是在编译时进行的。
结果分析: 1)是的,因为它们都包含相同的文字,所以生成的代码只有一个对象引用“Int32”。 见注1 。
2)为真,因为检查两个值的内容是相同的。
3)FALSE因为str2和obj没有相同的文字。 见注2 。