string和StringBuilder有什么区别?

时间:2012-05-19 02:35:22

标签: c# .net string stringbuilder

我知道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 个答案:

答案 0 :(得分:10)

  

由于两者都是参考类型,为什么它们会有不同的结果?

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

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

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

这种簿记发生在一个叫做“实习生表”的幕后,但这并不是你需要担心的事情。重要的是所有字符串文字都由编译器默认实现。

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

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

相关阅读:Optimizing C# String Performance

答案 1 :(得分:4)

宣布

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

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

另一方面,当你宣布

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

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

答案 2 :(得分:3)

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

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

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

答案 3 :(得分:1)

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

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

这是你比较他们的价值观的方法:

Console.WriteLine(sb1.ToString() == sb2.ToString());