Java源码系列 -- StringBuffer

一、类签名

相信看过 Java源码系列(2) -- StringBuilder 的读者都了解StringBuilderStringBuffer的异同,这里我们再复习一次加深印象。

public final class StringBuffer
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence

StringBuilderStringBuffer同样继承自AbstractStringBuilder父类,字符串序列增删查改等主要操作均在父类中实现。StringBuilder调用父类方法的时候,不会对正在进行的操作进行同步处理,而StringBuffer相反。一个同步锁的差异能影响多线程修改字符串序列的行为方式和线程处理过程中的性能。除此之外,他们俩都支持序列化。

二、数据成员

// 当字符串被修改之后,值最新缓存会被toString返回
private transient char[] toStringCache;
static final long serialVersionUID = 3388685877147921107L;

三、构造方法

默认创建长度为16的字符串序列,也可以自定义字符串序列长度。若用一个字符串为构造参数的话,构造方法会在原字符串上再加上16的缓冲长度。

public StringBuffer() {
    super(16);
}

public StringBuffer(int capacity) {
    super(capacity);
}

public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);
}

public StringBuffer(CharSequence seq) {
    this(seq.length() + 16);
    append(seq);
}

四、成员方法

为了保证线程安全,几乎所有方法都使用synchronized修饰符。同步锁加在这个字符串序列实例上,只要有一个线程已经占用这个实例,其他线程只能等待上一个线程释放同步锁再去竞争。

值得一提的是,synchronied锁有三种类别,分别是对象锁实例锁类锁对象锁是类中有一个静态常量Object对象作代码块锁的锁对象,只要同步代码块已经持有该对象,其他同步代码块只能等待上一个锁释放;实例锁的实例方法使用synchronied作为锁目标,只要该实例有一个同步方法在使用,其他线程对同一个实例同步操作只能等待上一个同步结束;类锁针对类静态方法需要使用线程同步的情况。由于静态类不需要初始化构造就能被访问,所以需要上锁的地方只能把整个类作为锁目标。

4.1 序列长

@Override
public synchronized int length() {
    return count;
}

@Override
public synchronized int capacity() {
    return value.length;
}

@Override
public synchronized void ensureCapacity(int minimumCapacity) {
    if (minimumCapacity > value.length) {
        expandCapacity(minimumCapacity);
    }
}

@Override
public synchronized void trimToSize() {
    super.trimToSize();
}

@Override
public synchronized void setLength(int newLength) {
    toStringCache = null;
    super.setLength(newLength);
}

4.2 查找

@Override
public synchronized char charAt(int index) {
    if ((index < 0) || (index >= count))
        throw new StringIndexOutOfBoundsException(index);
    return value[index];
}

@Override
public synchronized int codePointAt(int index) {
    return super.codePointAt(index);
}

@Override
public synchronized int codePointBefore(int index) {
    return super.codePointBefore(index);
}

@Override
public synchronized int codePointCount(int beginIndex, int endIndex) {
    return super.codePointCount(beginIndex, endIndex);
}

@Override
public synchronized int offsetByCodePoints(int index, int codePointOffset) {
    return super.offsetByCodePoints(index, codePointOffset);
}

@Override
public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
                                  int dstBegin)
{
    super.getChars(srcBegin, srcEnd, dst, dstBegin);
}

@Override
public int indexOf(String str) {
    // 备注:这个方法的同步依赖于其他StringBuffer方法的实现
    return super.indexOf(str);
}

@Override
public synchronized int indexOf(String str, int fromIndex) {
    return super.indexOf(str, fromIndex);
}

@Override
public int lastIndexOf(String str) {
    // 备注:这个方法的同步依赖于其他StringBuffer方法的实现
    return lastIndexOf(str, count);
}

@Override
public synchronized int lastIndexOf(String str, int fromIndex) {
    return super.lastIndexOf(str, fromIndex);
}

4.3 追加

@Override
public synchronized StringBuffer append(Object obj) {
    toStringCache = null;
    super.append(String.valueOf(obj));
    return this;
}

@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

/**
 * Appends the specified {@code StringBuffer} to this sequence.
 * <p>
 * The characters of the {@code StringBuffer} argument are appended,
 * in order, to the contents of this {@code StringBuffer}, increasing the
 * length of this {@code StringBuffer} by the length of the argument.
 * If {@code sb} is {@code null}, then the four characters
 * {@code "null"} are appended to this {@code StringBuffer}.
 * <p>
 * Let <i>n</i> be the length of the old character sequence, the one
 * contained in the {@code StringBuffer} just prior to execution of the
 * {@code append} method. Then the character at index <i>k</i> in
 * the new character sequence is equal to the character at index <i>k</i>
 * in the old character sequence, if <i>k</i> is less than <i>n</i>;
 * otherwise, it is equal to the character at index <i>k-n</i> in the
 * argument {@code sb}.
 * <p>
 * This method synchronizes on {@code this}, the destination
 * object, but does not synchronize on the source ({@code sb}).
 *
 * @param   sb   the {@code StringBuffer} to append.
 * @return  a reference to this object.
 * @since 1.4
 */
public synchronized StringBuffer append(StringBuffer sb) {
    toStringCache = null;
    super.append(sb);
    return this;
}

/**
 * @since 1.8
 */
@Override
synchronized StringBuffer append(AbstractStringBuilder asb) {
    toStringCache = null;
    super.append(asb);
    return this;
}

/**
 * Appends the specified {@code CharSequence} to this
 * sequence.
 * <p>
 * The characters of the {@code CharSequence} argument are appended,
 * in order, increasing the length of this sequence by the length of the
 * argument.
 *
 * <p>The result of this method is exactly the same as if it were an
 * invocation of this.append(s, 0, s.length());
 *
 * <p>This method synchronizes on {@code this}, the destination
 * object, but does not synchronize on the source ({@code s}).
 *
 * <p>If {@code s} is {@code null}, then the four characters
 * {@code "null"} are appended.
 *
 * @param   s the {@code CharSequence} to append.
 * @return  a reference to this object.
 * @since 1.5
 */
@Override
public synchronized StringBuffer append(CharSequence s) {
    toStringCache = null;
    super.append(s);
    return this;
}

@Override
public synchronized StringBuffer append(CharSequence s, int start, int end)
{
    toStringCache = null;
    super.append(s, start, end);
    return this;
}

@Override
public synchronized StringBuffer append(char[] str) {
    toStringCache = null;
    super.append(str);
    return this;
}

@Override
public synchronized StringBuffer append(char[] str, int offset, int len) {
    toStringCache = null;
    super.append(str, offset, len);
    return this;
}

@Override
public synchronized StringBuffer append(boolean b) {
    toStringCache = null;
    super.append(b);
    return this;
}

@Override
public synchronized StringBuffer append(char c) {
    toStringCache = null;
    super.append(c);
    return this;
}

@Override
public synchronized StringBuffer append(int i) {
    toStringCache = null;
    super.append(i);
    return this;
}

@Override
public synchronized StringBuffer appendCodePoint(int codePoint) {
    toStringCache = null;
    super.appendCodePoint(codePoint);
    return this;
}

@Override
public synchronized StringBuffer append(long lng) {
    toStringCache = null;
    super.append(lng);
    return this;
}

@Override
public synchronized StringBuffer append(float f) {
    toStringCache = null;
    super.append(f);
    return this;
}

@Override
public synchronized StringBuffer append(double d) {
    toStringCache = null;
    super.append(d);
    return this;
}

4.4 替换

@Override
public synchronized StringBuffer replace(int start, int end, String str) {
    toStringCache = null;
    super.replace(start, end, str);
    return this;
}

@Override
public synchronized void setCharAt(int index, char ch) {
    if ((index < 0) || (index >= count))
        throw new StringIndexOutOfBoundsException(index);
    toStringCache = null;
    value[index] = ch;
}

4.5 子序列

@Override
public synchronized String substring(int start) {
    return substring(start, count);
}

@Override
public synchronized CharSequence subSequence(int start, int end) {
    return super.substring(start, end);
}

@Override
public synchronized String substring(int start, int end) {
    return super.substring(start, end);
}

4.6 插入

@Override
public synchronized StringBuffer insert(int index, char[] str, int offset,
                                        int len)
{
    toStringCache = null;
    super.insert(index, str, offset, len);
    return this;
}

@Override
public synchronized StringBuffer insert(int offset, Object obj) {
    toStringCache = null;
    super.insert(offset, String.valueOf(obj));
    return this;
}

@Override
public synchronized StringBuffer insert(int offset, String str) {
    toStringCache = null;
    super.insert(offset, str);
    return this;
}

@Override
public synchronized StringBuffer insert(int offset, char[] str) {
    toStringCache = null;
    super.insert(offset, str);
    return this;
}


@Override
public StringBuffer insert(int dstOffset, CharSequence s) {
    // Note, synchronization achieved via invocations of other StringBuffer methods
    // after narrowing of s to specific type
    // Ditto for toStringCache clearing
    super.insert(dstOffset, s);
    return this;
}

@Override
public synchronized StringBuffer insert(int dstOffset, CharSequence s,
        int start, int end)
{
    toStringCache = null;
    super.insert(dstOffset, s, start, end);
    return this;
}

@Override
public  StringBuffer insert(int offset, boolean b) {
    // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
    // after conversion of b to String by super class method
    // Ditto for toStringCache clearing
    super.insert(offset, b);
    return this;
}

@Override
public synchronized StringBuffer insert(int offset, char c) {
    toStringCache = null;
    super.insert(offset, c);
    return this;
}

@Override
public StringBuffer insert(int offset, int i) {
    // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
    // after conversion of i to String by super class method
    // Ditto for toStringCache clearing
    super.insert(offset, i);
    return this;
}

@Override
public StringBuffer insert(int offset, long l) {
    // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
    // after conversion of l to String by super class method
    // Ditto for toStringCache clearing
    super.insert(offset, l);
    return this;
}

@Override
public StringBuffer insert(int offset, float f) {
    // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
    // after conversion of f to String by super class method
    // Ditto for toStringCache clearing
    super.insert(offset, f);
    return this;
}

@Override
public StringBuffer insert(int offset, double d) {
    // Note, synchronization achieved via invocation of StringBuffer insert(int, String)
    // after conversion of d to String by super class method
    // Ditto for toStringCache clearing
    super.insert(offset, d);
    return this;
}

4.7 翻转

@Override
public synchronized StringBuffer reverse() {
    toStringCache = null;
    super.reverse();
    return this;
}

4.8 删除

@Override
public synchronized StringBuffer delete(int start, int end) {
    toStringCache = null;
    super.delete(start, end);
    return this;
}

@Override
public synchronized StringBuffer deleteCharAt(int index) {
    toStringCache = null;
    super.deleteCharAt(index);
    return this;
}

4.9 toString

@Override
public synchronized String toString() {
    if (toStringCache == null) {
        toStringCache = Arrays.copyOfRange(value, 0, count);
    }
    return new String(toStringCache, true);
}

五、序列化

private static final java.io.ObjectStreamField[] serialPersistentFields =
{
    new java.io.ObjectStreamField("value", char[].class),
    new java.io.ObjectStreamField("count", Integer.TYPE),
    new java.io.ObjectStreamField("shared", Boolean.TYPE),
};

private synchronized void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException {
    java.io.ObjectOutputStream.PutField fields = s.putFields();
    fields.put("value", value);
    fields.put("count", count);
    fields.put("shared", false);
    s.writeFields();
}

private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    java.io.ObjectInputStream.GetField fields = s.readFields();
    value = (char[])fields.get("value", null);
    count = fields.get("count", 0);
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 7,063评论 0 62
  • 今天闺女比较乖,一向周末不午睡的她,在我的“威逼利诱”下睡到现在还没醒。日语学习任务基本完成,提前来更文。 单词及...
    诺凡阅读 354评论 0 5
  • 忧忧把晨读写成自己的成长感悟。 “这件事你说我自己知道答案?怎么可能?我要是知道答案我干嘛还要来问你?扯淡!” “...
    Mjinxiu无忧阅读 1,373评论 3 10
  • 我们每天都会遇到大大小小的各种事情需要去决定,家庭中的,工作中的等等,决定成为我们生活中一件非常重要的事,尤其是重...
    常知了了阅读 311评论 0 0