我今天看到,C#中的字符串是不可变的,一旦创建就无法更改,那么下面的代码为什么会起作用呢?
string str="a";
str +="b";
str +="c";
str +="d";
str +="e";
console.write(str) //output: abcde
为什么变量的值会改变?
我今天看到,C#中的字符串是不可变的,一旦创建就无法更改,那么下面的代码为什么会起作用呢?
string str="a";
str +="b";
str +="c";
str +="d";
str +="e";
console.write(str) //output: abcde
为什么变量的值会改变?
字符串对象是不可变的,但变量可以被重新分配。
你创建了单独的对象
a
ab
abc
abcd
abcde
每个不可变字符串都按顺序被赋值给变量str。很容易证明这篇文章并没有像人们所认为的那样改变了String对象:
string a = "a";
string b = a;
Console.WriteLine(object.ReferenceEquals(a, b)); // true
Console.WriteLine(a); // a
Console.WriteLine(b); // a
b += "b";
Console.WriteLine(object.ReferenceEquals(a, b)); // false
Console.WriteLine(a); // a
Console.WriteLine(b); // ab
x += y
运算符相当于x = x + y
,但输入的内容更少。str = "a" + "b" + "c" ...
str = "abc"
Immutable意味着用于存储字符串变量的内存位置永远不会改变。
string str ="a"; //stored at some memory location
str+= "b"; // now str='ab' and stored at some other memory location
str+= "c"; // now str='abc' and stored at some other memory location
string a="Hello";
string b=a;
a="changed";
console.writeline(b);
你好,变量 b
仍然引用原始位置。
请查看 John Skeet 的页面。
概念:
变量和实例是两个不同的概念。变量是保存值的东西。对于字符串来说,变量保存指向存储在其他地方的字符串的指针:即实例。
变量总是可以被分配和重新分配的,正如它名字所暗示的那样!=)
实例,就像我刚才说的,存在于其他地方,在字符串的情况下,它是不可更改的。
通过像您所做的那样连接字符串,实际上会创建许多不同的存储,每个字符串连接一个存储。
正确的方法:
要连接字符串,可以使用StringBuilder类:
StringBuilder b = new StringBuilder();
b.Append("abcd");
b.Append(" more text");
string result = b.ToString();
List<string> l = new List<string>();
l.Add("abcd");
l.Add(" more text");
string result = string.Join("", l);
@pst - 我同意可读性很重要,在大多数情况下,它在电脑上不会有影响,但如果您在系统资源受限的移动平台上呢?
重要的是要明白StringBuilder是连接字符串的最佳方式。它更快、更高效。
您强调了一个重要的区别,即它是否明显 更快,并在哪些场景中。令人印象深刻的是,这种差异必须以低体积的滴答声来测量,因为无法以毫秒来测量。
重要的是要知道,在桌面平台的日常场景中,这种差异是不可感知的。但也很重要,对于构建大型字符串或执行数千个连接的边缘情况,或者进行性能优化,StringBuilder确实胜出。在非常大量的连接中,值得注意的是StringBuilder需要稍微更多的内存。
这绝不是一个完美的比较,但对于那些连接1,000,000个字符串的傻瓜来说,StringBuilder比普通的字符串连接要快约10分钟(在Win7 x64上使用Core 2 Duo E8500 @ 3.16GHz):
String concat (10): 9 ticks, 0 ms, 8192 bytes
String Builder (10): 2 ticks, 0 ms, 8192 bytes
String concat (100): 30 ticks, 0 ms, 16384 bytes
String Builder (100): 6 ticks, 0 ms, 8192 bytes
String concat (1000): 1658 ticks, 0 ms, 1021964 bytes
String Builder (1000): 29 ticks, 0 ms, 8192 bytes
String concat (10000): 105451 ticks, 34 ms, 2730396 bytes
String Builder (10000): 299 ticks, 0 ms, 40624 bytes
String concat (100000): 15908144 ticks, 5157 ms, 200020 bytes
String Builder (100000): 2776 ticks, 0 ms, 216888 bytes
String concat (1000000): 1847164850 ticks, 598804 ms, 1999804 bytes
String Builder (1000000): 27339 ticks, 8 ms, 2011576 bytes
代码:
class Program
{
static void Main(string[] args)
{
TestStringCat(10);
TestStringBuilder(10);
TestStringCat(100);
TestStringBuilder(100);
TestStringCat(1000);
TestStringBuilder(1000);
TestStringCat(10000);
TestStringBuilder(10000);
TestStringCat(100000);
TestStringBuilder(100000);
TestStringCat(1000000);
TestStringBuilder(1000000);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
static void TestStringCat(int iterations)
{
GC.Collect();
String s = String.Empty;
long memory = GC.GetTotalMemory(true);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
s += "a";
}
sw.Stop();
memory = GC.GetTotalMemory(false) - memory;
Console.WriteLine("String concat \t({0}):\t\t{1} ticks,\t{2} ms,\t\t{3} bytes", iterations, sw.ElapsedTicks, sw.ElapsedMilliseconds, memory);
}
static void TestStringBuilder(int iterations)
{
GC.Collect();
StringBuilder sb = new StringBuilder();
long memory = GC.GetTotalMemory(true);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
sb.Append("a");
}
sw.Stop();
memory = GC.GetTotalMemory(false) - memory;
Console.WriteLine("String Builder \t({0}):\t\t{1} ticks,\t{2} ms,\t\t{3} bytes", iterations, sw.ElapsedTicks, sw.ElapsedMilliseconds, memory);
}
}
实际上它并没有,它只是用新值覆盖了变量,每次都创建了一个新的字符串对象。
不变性意味着类不能被修改。对于每个 += 操作,你都在创建一个全新的字符串对象。
+=
的原因是:1)它对我来说通常更清晰;2)这其实不重要。 - user166390