6

我知道这string是不可变的并且StringBuilder是可变的。但是任何人都可以解释以下代码输出吗?既然都是引用类型,为什么会有不同的结果呢?

String s1 = "hello";
String s2 = "hello";
Console.WriteLine(s1 == s2); //true
Console.WriteLine(Object.ReferenceEquals(s1, s2)); //true

StringBuilder sb1 = new StringBuilder("hello");
StringBuilder sb2 = new StringBuilder("hello");
Console.WriteLine(sb1 == sb2); //false
Console.WriteLine(Object.ReferenceEquals(sb1,  sb2)); //false
4

4 回答 4

10

既然都是引用类型,为什么会有不同的结果呢?

因为string对象是高度优化的。特别是,由于它们是不可变的,编译器可以对它们进行实习以防止重复。

如果您有两个不同string的对象,它们都表示完全相同的字符串(如您的示例中所示),编译器将识别这一点并仅维护实际字符串对象的一个​​实例。

结果是,就编译器而言, thes1和对象实际上都是同一个对象,甚至引用内存中的相同位置。s2

这种簿记发生在称为“实习生表”的幕后,但这并不是您真正需要担心的事情。重要的是所有字符串文字都默认由编译器进行实习。

对象不会发生同样的事情StringBuilder,因为它们不是不可变的。它们旨在允许您修改字符串对象,因此,优化没有多大意义。这就是为什么您的sb1sb2对象实际上被视为两个不同的对象。

经验法则非常简单:string默认使用,或者当您需要单个不可变字符串时使用。仅StringBuilder在您想多次修改同一个字符串时使用,例如在循环或其他相对较短的代码段中。

相关阅读:优化 C# 字符串性能

于 2012-05-19T02:40:32.753 回答
4

当你声明

String s1 = "hello";
String s2 = "hello";

编译器足够聪明,知道这两个字符串是(并且将永远是)相同的,因此它只存储"hello"一次并创建s1s2作为同一物理内存的别名。稍后,当您测试相等性时,两者相等,因为它们本质上是相同的变量。

另一方面,当您声明

StringBuilder sb1 = new StringBuilder("hello");
StringBuilder sb2 = new StringBuilder("hello");

编译器创建两个变量(因为它们都是可变的,但恰好被初始化为相同的值)。它将字符串复制"hello"到其中的每一个中,但现在有 2 个副本,因为以后可能会更改每个副本。因此,即使它们的内容相同,它们也是 2 个不同的实体,位于不同的物理内存位置,因此对象相等性测试失败。

于 2012-05-19T02:43:23.813 回答
3

默认情况下,当比较两个引用类型的对象时,只有当两个引用相等时结果才为,这意味着两个操作数必须引用相同的对象实例。因为 sb1 和 sb2 引用的对象是两个不同的对象,所以 StringBuilders 比较的结果是 false。

但是 String 类以这样一种方式覆盖了相等运算符,它不会通过引用来比较对象,而是通过它们的值来比较对象,因为这种行为非常直观并且是程序员所期望的。这就解释了为什么 s1 == s2 返回 true。

Object.ReferenceEquals(s1, s2) 也返回 true 的原因(尽管 s1 和 s2 似乎引用了不同的字符串实例)称​​为字符串实习。它导致 CLR 将所有出现的相同字符串文字(例如您的示例中的“hallo”和“hallo”)放入每个应用程序的内部字符串池一次,因此 s1 和 s2 实际上都引用了字符串“hallo”的相同实例. 这是可能的,因为字符串是不可变的。

于 2012-05-19T03:10:22.927 回答
1

当您执行以下操作时,您正在比较两个不同的 StringBuilder 对象而不是它们的值:

StringBuilder sb1 = new StringBuilder("hello");
StringBuilder sb2 = new StringBuilder("hello");
Console.WriteLine(sb1 == sb2); //false

这是您可以比较它们的值的方式:

Console.WriteLine(sb1.ToString() == sb2.ToString());
于 2012-05-19T02:40:07.017 回答