C#中的string和StringBuilder之间的区别


71

string和之间有什么区别StringBuilder

另外,有什么例子可以理解?




5
@乔治:实际上,第一个问题是相当狭窄的,甚至以“我已经知道区别”开头-这个问题专门提出了这个问题。
乔伊(Joey)

1
@乔治:我不敢相信这不会出现在相关侧边栏中。
比尔蜥蜴

1
@约翰内斯:那更好。我同意这与其他任何链接的问题都不完全相同,但这可能只是因为这个问题有点含糊。
比尔蜥蜴

Answers:


106

一个string实例是不可变的。创建后便无法更改。似乎更改字符串的任何操作都将返回一个新实例:

string foo = "Foo";
// returns a new string instance instead of changing the old one
string bar = foo.Replace('o', 'a');
string baz = foo + "bar"; // ditto here

不可变对象具有一些不错的属性,例如可以在线程中使用它们而不必担心同步问题,或者您可以直接直接分发私有支持字段,而不必担心有人更改了不应更改的对象(请参见数组或可变列表,如果不需要的话,通常需要在返回之前将其复制)。但是,如果不小心使用它们,可能会导致严重的性能问题(几乎所有问题–如果您需要一个以执行速度而自豪的语言为例,请查看C的字符串操作函数)。

当您需要可变的字符串(例如,您要分段构造的字符串或要在其中进行很多更改的地方)时,您将需要一个StringBuilder,它是可以更改的字符缓冲区。在大多数情况下,这会影响性能。如果您想要一个可变的字符串,而不是对一个普通的string实例进行处理,那么最终将不必要地创建和销毁许多对象,而StringBuilder实例本身将发生变化,从而消除了对许多新对象的需求。

一个简单的例子:以下内容将使许多程序员感到痛苦:

string s = string.Empty;
for (i = 0; i < 1000; i++) {
  s += i.ToString() + " ";
}

您最终将在此处创建2001个字符串,其中的2000个将被丢弃。使用StringBuilder的相同示例:

StringBuilder sb = new StringBuilder();
for (i = 0; i < 1000; i++) {
  sb.Append(i);
  sb.Append(' ');
}

这应该减轻内存分配器的压力:-)

但是,应注意的是,在涉及字符串时,C#编译器相当聪明。例如,以下行

string foo = "abc" + "def" + "efg" + "hij";

将由编译器加入,在运行时仅保留一个字符串。类似地,诸如

string foo = a + b + c + d + e + f;

将被重写为

string foo = string.Concat(a, b, c, d, e, f);

因此您不必为五个无意义的连接付费,这是处理该问题的幼稚方式。这不会像上面那样在循环中节省您的时间(除非编译器展开循环,但我认为只有JIT可以这样做,最好不要对此押注)。


“任何似乎更改字符串的操作都会返回一个新实例”,但是为什么呢?是什么原因?为什么字符串不是可变的?为什么CLR创建新实例并删除以前的实例?
AminM 2013年

5
@Jeson:不可变数据结构具有很多不错的属性,其中大多数与默认情况下编写更安全的代码有关。您不必担心字符串会因为另一个线程在工作而改变。而且,您不必返回类的内部字符串的副本即可防止使用者篡改您的字段。
乔伊(Joey)2013年

8

字符串与StringBuilder

    • 在系统名称空间下

    • 不可变(只读)实例

    • 当价值不断变化时,性能会下降

    • 线程安全

  • StringBuilder(可变字符串)

    1. 在System.Text命名空间下
    2. 可变实例
    3. 由于对现有实例进行了新更改,因此显示了更好的性能

有关此主题的描述性的文章有很多的例子使用ObjectIDGenerator,遵循此链接

相关的堆栈溢出问题:当C#中的字符串不变时,字符串的可变性


6

字符串是不可变的,这意味着创建字符串时永远无法更改它。相反,它将创建一个新的字符串来存储新值,如果您需要大量更改字符串变量的值,这可能会效率低下。

StringBuilder可用于模拟可变字符串,因此它在需要大量更改字符串时非常有用。


4

String实例是不可变的,也就是说,创建后我们无法更改它。如果我们对String执行任何操作,它将返回一个新实例(在内存中创建一个新实例),而不是修改现有实例值。

StringBuilder

StringBuilder是可变的,也就是说,如果我们在StringBuilder上执行任何操作,它将更新现有实例值,并且不会创建新实例。

String和StringBuilder之间的区别


2

StringBuilder类文档中

String对象是不可变的。每次使用System.String类中的一种方法时,都会在内存中创建一个新的字符串对象,这需要为该新对象分配新的空间。在需要对字符串进行重复修改的情况下,与创建新的String对象相关的开销可能会非常昂贵。当您要修改字符串而不创建新对象时,可以使用System.Text.StringBuilder类。例如,当将多个字符串串联在一起时,使用StringBuilder类可以提高性能。


2

当您需要分多个步骤构建字符串时,StringBuilder将为您提供帮助。

而不是这样做:

String x = "";
x += "first ";
x += "second ";
x += "third ";

你做

StringBuilder sb = new StringBuilder("");
sb.Append("first ");
sb.Append("second ");
sb.Append("third");
String x = sb.ToString();

最终效果是相同的,但是StringBuilder将使用更少的内存并且运行得更快。与其创建一个新的字符串(不是两者的串联),它会分别创建块,并且只有在最后才将它们组合在一起。


1

主要区别:

字符串是不可变的。这意味着您根本无法修改字符串。修改的结果是一个新的字符串。如果您打算追加到字符串,则此方法无效。

StringBuilder是可变的。可以以任何方式对其进行修改,并且不需要创建新实例。工作完成后,可以调用ToString()以获取字符串。

字符串可以参与实习。这意味着具有相同内容的字符串可能具有相同的地址。StringBuilder无法被拘禁。

字符串是唯一可以具有引用文字的类。


1

字符串是不可变的,即,如果更改它们的值,则旧值将被丢弃,并在堆上创建新值,而在字符串生成器中,我们可以修改现有值而无需创建新值。

因此,性能方面的String Builder是有益的,因为我们不需要占用更多的内存空间。


0

字符串(System.String)是.NET框架内定义的类型。String类是不可变的。这意味着每次对System.String实例执行操作时,.NET编译器都会创建该字符串的新实例。该操作对开发人员隐藏。

System.Text.StringBuilder是表示可变字符串的类。此类提供了一些有用的方法,这些方法使用户能够管理由StringBuilder包装的String。请注意,所有操作都在同一StringBuilder实例上进行。

Microsoft鼓励使用StringBuilder,因为它在内存使用方面更为有效。


0

同样,字符串连接的复杂度为O(N2),而对于StringBuffer,复杂度为O(N)。

因此,由于每次都会创建许多新对象,因此在循环中使用串联时可能会出现性能问题。


0

Clone如果要迭代字符串以及字符串生成器,则可以使用该方法。它返回一个对象,因此您可以使用ToString方法转换为字符串... :)



0

字符串是不可变的类型。这意味着,每当您开始将字符串彼此串联时,每次都会创建新的字符串。如果执行多次,最终将导致大量堆开销和内存不足的风险。

StringBuilder实例用于将字符串追加到同一实例,从而在您调用ToString方法时创建一个字符串。

由于实例化StringBuilder对象的开销,Microsoft表示,当您有5-10个以上的字符串串联时,使用它很有用。

对于示例代码,我建议您在这里看看:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.