string
和 StringBuilder
有什么区别?
此外,有哪些例子可以帮助理解?
string
和 StringBuilder
有什么区别?
此外,有哪些例子可以帮助理解?
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
Immutable对象有一些好的特性,例如它们可以在不担心同步问题的情况下跨线程使用,或者您可以直接分配私有备份字段而不担心其他人更改不应更改的对象(例如数组或可变列表,如果不需要则通常需要复制它们)。但是,如果不小心使用,则可能会创建严重的性能问题(几乎任何东西都是如此——如果您需要一个以执行速度自豪的语言的示例,请查看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可能会这样做,最好不要抱有此期望)。
String
在 System 命名空间下
不可变(只读)实例
当连续更改值时性能会降低
线程安全
StringBuilder(可变字符串)
有关此主题的描述性文章,并使用ObjectIDGenerator的许多示例,请访问此链接。
相关的 Stack Overflow 问题:当字符串在 C# 中不变时,字符串的可变性
字符串是不可变的,这意味着当你创建一个字符串后,你永远不能改变它。相反,它会创建一个新的字符串来存储新值,如果你需要频繁更改字符串变量的值,则这可能效率低下。
StringBuilder可以用来模拟可变字符串,因此在需要经常更改字符串时非常有用。
字符串
字符串实例是不可变的,这意味着创建之后就不能更改。如果我们对一个字符串执行任何操作,它将返回一个新的实例(在内存中创建一个新实例),而不是修改现有实例的值。
字符串生成器
字符串生成器是可变的,也就是说,如果我们对字符串生成器执行任何操作,它会更新现有实例的值,而不会创建一个新的实例。
主要区别:
String是不可变的。这意味着您根本无法修改字符串;修改的结果是一个新字符串。如果您计划添加到字符串中,则此方法并不有效。
StringBuilder是可变的。它可以以任何方式进行修改,而且不需要创建新实例。完成工作后,可以调用ToString()来获取字符串。
字符串可以参与内部化。这意味着具有相同内容的字符串可能具有相同的地址。StringBuilder不能被内部化。
String是唯一可以具有引用字面量的类。
String x = "";
x += "first ";
x += "second ";
x += "third ";
you do
StringBuilder sb = new StringBuilder("");
sb.Append("first ");
sb.Append("second ");
sb.Append("third");
String x = sb.ToString();
字符串是不可变的,如果你改变它们的值,旧值将被丢弃并在堆上创建一个新值。而在字符串构建器中,我们可以修改现有的值而不会创建新值。
因此,从性能方面考虑,字符串构建器是有益的,因为我们不需要占用更多的内存空间。
字符串的连接复杂度为O(N2),而StringBuffer的复杂度为O(N)。
因此,在循环中使用连接操作可能会导致性能问题,因为每次都会创建大量新对象。
如果您想要在字符串生成器中迭代字符串,可以使用Clone
方法...该方法会返回一个对象,因此您可以使用ToString方法将其转换为字符串...:)