深入了解C#,我遇到了一个与对象引用相等的小问题。 我说我有两个字符串:
String a = "Hello world!";
String b = "Bonjour le monde";
bool equals = ReferenceEquals(a, b); // ******************* (1)
b = "Hello world!";
equals = ReferenceEquals(a, b); // ******************* (2)
(1)
false
是预期的。
ReferenceEquals Documentation说
ReferenceEquals比较实例
然后:
true
?a
和b
不是同一个对象吗?如果是,那么它们是如何变得相同的,因为我从未明确地做a=b
答案 0 :(得分:24)
这是因为string interning。
公共语言运行库通过维护a来保存字符串存储 表,称为实习池,包含单个引用 以编程方式声明或创建的每个唯一文字字符串 你的计划。因此,带有一个文字字符串的实例 特殊值仅在系统中存在一次。
例如,如果将相同的文字字符串分配给多个 变量,运行时检索对文字的相同引用 来自实习池的字符串,并将其分配给每个变量。
答案 1 :(得分:9)
.NET运行时自动为interned字符串文字。这意味着对具有相同值的字符串文字共享相同的字符串实例。这样做是为了减少内存使用并提高性能。这是一个安全的优化,因为字符串是不可变的。
您的代码会编译为CIL指令,类似于以下内容:
IL_0001: ldstr "Hello world!"
IL_0006: stloc.0
IL_0007: ldstr "Bonjour le monde"
IL_000c: stloc.1
etc...
从ECMA specification中的ldstr
(“加载文字字符串”)说明文档:
默认情况下,CLI保证两个ldstr指令的结果引用两个元数据标记 具有相同的字符序列,返回完全相同的字符串对象(称为“字符串”的过程 interning“)。可以使用
System.Runtime.CompilerServices.CompilationRelaxationsAttribute
和System.Runtime.CompilerServices.CompilationRelaxations.NoStringInterning
来控制此行为。
您也可以通过调用方法String.Intern来实习自己。
答案 2 :(得分:4)
字符串文字大多数时候都是同一个对象,因为它们是常量和不可变的。
每个字符串文字不一定会产生新的字符串 实例。当两个或多个字符串文字相同时 根据字符串相等运算符(第7.9.7节)出现 在相同的程序集中,这些字符串文字引用相同的字符串 实例。例如,
产生的输出
class Test
{
static void Main() {
object a = "hello";
object b = "hello";
System.Console.WriteLine(a == b);
}
}
为True,因为两个文字引用相同的字符串实例。
答案 3 :(得分:3)
.NET维护一个字符串池,因为它们是不可变的。你不必关心它,因为它自己需要重用它们。