java依旧提供了可变字符串 StringBuffer类,java分开提供两种操作方式在我认为,就是要告诉用户,在java中,可变长字符串的操作是效率比较低下的,所以如果没有 需要,那么使用String类就好,我觉得,重新创建一个新的String实例也许也比在已有的堆中作动态内存调整要高效得多。当然,这些仅仅都是“我认 为”而已。 在考察源代码的时候,我发现了java是通过下述几种途径来操作StringBuffer类的。 1、首先在分配空间的时候采取多分配的策略,除非用户指定分配空间的大小,否则分配的空间总是比用户需求的数量多32个字节(16个char)。 2、其次,在追加空间长度的时候采用多分配的策略,本着分配新空间的长度不小于 (原空间长度 + 1)* 2的原则分配新的字符数组空间,如果用户指定新的空间大小大于这个数字,则按照用户指定大小追加空间,否则按照这个数字追加空间,称之为“保守策略”。 3、采用本地源生代码进行数据复制,StringBuffer类采用System.arraycopy方法进行数据复制,而该方法是一个native方法,也就是使用c语言编写的二进制方法,可以充分的利用诸如Intel处理器的movs等指令高速复制内存。 从源代码中也可以看到,每次进行insert,replace等等方法的时 候,StringBuffer类都要考察实际空间大小,如果需求小于等于实际空间大小,则直接进行操作,否则就要放弃当前内存空间的引用,重新分配空间, 并且将原有数据进行拷贝,这个策略被C++标准库的vector容器一直使用着,但java毕竟不是C++,所以从效率上,java出于一个比较尴尬的处 境,在条件允许的情况下,尽量使用String类而不是 StringBuffer类才是上上策。 StringBuffer提供了许多String类已经提供的功能,这是为了方便用户,而更多的新功能现简要说明如下: StringBuffer.StringBuffer构造器,允许从任意种数据类型构造StringBuffer类。 StringBuffer.append方法可以将一个字符串追加到原有字符串之后,该方法重载了多次,参数可以是任何一种简单对象或者重载了toString方法的Object类的子类。 StringBuffer.capacity可以得到缓冲区的长度;而StringBuffer.length可以得到字符串的实际长度。 StringBuffer.charAt可以得到字符串中的任意一个字符,抛出tringIndexOutOfBoundsException 异常。 StringBuffer.delete可以删除字符串中任意一个字符,删除完毕后对缓冲区长度没有影响,该方法抛出StringIndexOutOfBoundsException异常。 StringBuffer.ensureCapacity可以增加缓冲区的长度,但不允许减少它,增加的数字按照上面所说的保守策略进行。 StringBuffer.insert可以插入一个字符串到原有的字符串的指定位置中,这个方法同样也被重载了多次,以适应不同的数据类型,可能会抛出StringIndexOutOfBoundsException异常。 StringBuffer.reverse将会倒置字符串,采用的是《编程珠玑》中提到的一种翻转算法,用一个char的缓冲区经过多次叠代就可以达到目的。 StringBuffer.setCharAt可以在已有字符串的任意一个位置重新设置字符,抛出StringIndexOutOfBoundsException异常。 StringBuffer.substring的作用和在String类中相同。 StringBuffer.setLength可以改变缓冲区的大小,不采用保守策略,直接按照用户意愿改变缓冲区大小,如果缓冲区大小比原先的要小,则不会保留多余的内容。 可以发现,许多方法需要抛出StringIndexOutOfBoundsException异常,这个异常其实是char数组抛出的,表示下标访问越界异常,如果用心操作StringBuffer类,这个异常是决不会引发的,所以这个异常是一个选择性捕获的异常。 StringBuffer类的大部分方法被标记为synchronized方法,在多线程中可以确保同步。