【问题标题】:What is the difference between string and StringBuilder?string 和 StringBuilder 有什么区别?
【发布时间】:2012-05-26 13:46:21
【问题描述】:

我知道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

【问题讨论】:

  • 您正在比较两个不同的 StringBuilder 对象引用。它们是两个独立的对象。
  • +1,不仅是因为一个很好的问题,而且因为它问得如此清楚,并附有一个完整的代码示例,并且被完美地注释了。
  • 这个问题其实和StringBuilder无关。它实际上是关于“为什么用包含相同字符序列的两个字符串文字初始化的两个字符串变量比较为同一个对象”?
  • 使用string s2 = "hel" + "lo"; 看看它与类型没有任何关系。

标签: c# .net string stringbuilder


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

    因为string 对象是高度优化的。特别是,由于它们是不可变的,因此它们可以被编译器拦截以防止重复。

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

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

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

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

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

    相关阅读:Optimizing C# String Performance

    【讨论】:

      【解决方案3】:

      当你声明时

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

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

      另一方面,当你声明时

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

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

      【讨论】:

        【解决方案4】:

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-11-29
          • 1970-01-01
          • 2011-02-24
          • 2016-11-09
          • 1970-01-01
          • 2016-03-26
          • 2019-07-08
          • 2021-12-21
          相关资源
          最近更新 更多