一、字符串常量的特性
下面的代码创建了几个对象?
很明显,创建了三个对象。只要是用new 创建的对象,都是一个 新对象。那s3,s4怎么是一个对象呢?这和字符串常量的特性有关。
字符串常量存储在字符串暂存池中,以键值对的形式存储,键中存储字符串的内容,值中存储字符串的地址。当我们使用某个字符串常量的时候,首先会去暂存池中查找这个字符串是否存在,如果存在,直接返回键值对中的value.字符串常量的这个特性依赖于字符串的不可变性实现。
再看另一个例子 :
上面的代码只创建了一个对象。为何s5和前面的是一个对象?
再变化一下:
很明显创建了5个对象。对于string s2=a+b+c;这句代码,因为a,b,c是变量 ,在这之前可能重新赋值,所以相加后是个新的对象,而string s5="a"+"b"+"c";是三个固定的值相加,所以合并后和s4是同一个变量。这个结论只适合字符串常量。
二、字符串的不可变性

1 #region 字符串的不可变性 2 string s1 = "abc"; 3 s1 = "cba"; 4 Console.WriteLine(s1); 5 #endregion
上面的代码中,先是在内存中开辟了一块内存,存储abc,然后让s1指向这块内存,然后又开辟了块内存,存储cba,让s1指向新开辟的内存。开辟的两块内存在程序退出前是一直存在的,只是我们只输出了新开辟的内存中的内容。当给一个变量新赋值一个字符串的时候,原来的内存中的字符串的内容不会改变,这就是字符串的不可变性。
下面的代码在内存中开辟了多少块内存?

1 string s = "a"; 2 s = s + "b"; 3 s = s + "c"; 4 s = s + "d"; 5 Console.WriteLine(s);
7块。因为不是对字符串常量进行操作,所以每次给s加上一个字符串的时候,出了新开辟的b,c,d所占的内存外,还会给拼接的字符串开辟内存。由此,可见,用这种方式拼接字符串是相当耗资源的。
tips:
1.声明字符串开辟的内存,只有当程序退出后,才会释放,所以不要把大文本字符串用变量保存起来。可以先把大文本保存到一个txt文件中,用对应的方法读取,方法执行完成后,就释放了资源,能提高程序的性能。
2.拼接字符串可用stringbuilder对象。
下面的代码可以看出string 和stringbuilder的性能的差距;

1 //string s = string.Empty; 2 StringBuilder s = new StringBuilder(); 3 Stopwatch stop = new Stopwatch(); 4 stop.Start(); 5 for (int i = 0; i < 200000; i++) 6 { 7 //s += "a";////00:00:14.3903122 8 s.Append("a");//00:00:00.0025962 9 } 10 stop.Stop(); 11 Console.WriteLine(stop.Elapsed); 12 Console.WriteLine("ok");