1 - 引言
在 Java 中,String 被设置为不可变类,JDK 开发人员很小心地保证 String 的底层存储结构 private final char[] value
不被修改。所有对字符串的直接赋值操作,实际上都将字符串变量指向了新的 String 对象。
对于需要对字符串进行大量修改的程序来说,例如对字符串进行拼接,会产生很多无用的 String 实例,所以我们常常会使用 StringBuffer 或者 StringBuilder 来取代 String。
2 - StringBuilder 和 StringBuffer
这两个类其实在实现上是大同小异的,主要的区别就是 StringBuffer 在绝大部分必要的方法上添加了 synchronized 关键字,所以 StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的。在单线程应用中,使用哪一个问题都不大,但 StringBuffer 使用同步锁会损失一部分性能,这一点也是需要知道的。(有点像 HashMap 和 HashTable)
先观察这两个类的声明,我们发现它们继承相同的父类和实现相同的接口,同时两个类几乎没有自己定义的成员变量。
public final class StringBuffer extends AbstractStringBuilder
implements java.io.Serializable, CharSequence {
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache; // 这个cache在本文不讨论
static final long serialVersionUID = 3388685877147921107L;
...
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
...
}
public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, CharSequence {
static final long serialVersionUID = 4383685877147921099L;
...
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
...
}
观察两个类的其他方法,我们发现大部分的方法都是直接调用父类已经定义好的方法,所以StringBuilder 和 StringBuffer 的研究我们先放下,将注意力放在它们的父类 AbstractStringBuilder 上。
3 - AbstractStringBuilder 的值修改
首先我们比较关心 AbstractStringBuilder 的成员变量,或者说关心他底层实际的存储结构,可以猜想,肯定是一个 char 数组,情况也确实如此,如下:
abstract class AbstractStringBuilder implements Appendable, CharSequence {