二十八:使用StringBuilder类型
由于String类型代表的是一个不可变的字符串,所以FCL提供了另一个名为System.Text.StringBuilder的类型,它允许我们有效的对字符串的字符执行动态操作,以创建一个String。从逻辑上说,StringBuilder对象中包含一个字段,它引用由Char结构构成的一个数组。StringBuilder的成员允许我们操作这个字符,有效的缩减字符串的大小或者更改字符串中的字符。如果字符串变大,超过已经分配的字符的大小,StringBuilder就会自动的分配一个全新的、更大的数组,并开始使用新的数组,前一个数组会被垃圾回收器回收。
用StringBuilder对象构建好字符串之后,为了将StringBuilder的字符“转换”成一个String,只需调用StringBuilder的ToString方法,在内部,该方法只是返回对StringBuilder内部维护的字符串的字段的一个引用,执行效率非常快,因为它不需要进行字符数组复制。
大多数编程语言(包括C#)都不将StringBuilder类视为一个基类型,所以我们要像构造其它非基元类型那样构建StringBuilder对象。
StringBuilder sb = new StringBuilder();
StringBuilder类型提供了很多构造器,每个构造器的职责是分配和初始化由每个StringBuilder对象维护的状态:
最大容量:一个Int32值,它指定了可以放在一个字符串中的最大字符数,默认值是Int32.MaxValue(约为20亿)。一般不用更改这个值,但是可能需要指定一个较小的最大容量,以确保永远不会创建一个超出特定长度的字符串,一旦构造好之后,StringBuilder的最大容量就固定下来不能再改变了。
容量:一个Int32值,它指定了可由StringBuilder维护的字符数组长度。默认为16,如果事先知道要在StringBuilder中放入多少字符,那么在构造StringBuilder对象的时候,应该使用这个数字来设置好容量。将字符串加到字符数组时,StringBuilder会检测数组会不会超过设定的容量,如果会,StringBuilder会自动倍增容量字段,使用一个新的容量分配一个新的数组,并将原始的字符复制到新的数组中,随后,原始数组可以被垃圾器收集,此过程会损害性能,所以在构建StringBuilder对象时要设置一个合适的初始容量。
字符数组:一个由Char结构构成的数组,它负责维护“字符串”中的字符集。构造一个StringBuilder时,可以传递一个String来初始化字符数组,如果不传递一个字符串,数组刚开始就不包含任何字符,也就是说Length属性会返回0。
和String不同,StringBuilder代表的是一个可变的字符串,也就是说StringBuilder的大多数成员都会修改字符数组中的内容,同时不会在托管堆上分配新的对象,StringBuilder只在以下两种情况下公分配一个新的对象:
(1)试图动态的构造一个字符串,它的长度超过了事先设定的“容量”
(2)试图在调用StringBuilder的ToString方法之后修改数组
StringBuilder的大多数方法返回的都是到相同StringBuilder对象的一个引用,所以,可以把以下几个操作链接到一起完成:
StringBuilder sb = new StringBuilder();
String s=sb.AppendFormat("{0} {1}","hellow","world").Replace(' ','-').Remove(4,3).ToString();
Console.WriteLine(s);
String和StringBuilder类提供的方法并不是完全配对的,例如,String提供了ToLower,ToUpper,EndsWith,PadLeft,PadRight,Trim等方法,但StringBuilder类没有提供任何与之对应的方法。另一方面StringBuilder类提供了一个功能更全面的Replace方法,它允许替换作为一个字符串的一部分的字符或者字符串(而不是一定要替换整个字符串)。由于这两个类不完全对应,所以经常在它们俩之间转换以便完成任务。例如,为了构造一个字符串,将所有的字符转换成大写,然后在其中插入一个字符串,需要下面这样的代码:
StringBuilder sb = new StringBuilder();
//使用StringBuilder来执行一些字符串操作
sb.AppendFormat("{0} {1}", "hellow", "world").Replace(' ', '-');
//将StringBuilder转换成String,以便将所有字符转换成大写
String s = sb.ToString().ToUpper();
//清除StringBuilder(分配一个新的Char数组)
sb.Length = 0;
//将全部大写的String加载到StringBuilder中
sb.Append(s).Insert(7, "Test-");
//将StringBuilder转换成String
s = sb.ToString();
Console.WriteLine(s);//显示HELLOW-Test-WORLD