Java StringBuffer和StringBuilder

作者:ouyangyewei
个人站点:http://ouyangyewei.me/


简介

StringBuffer和StringBuilder,两者都是可变对象,都继承java.lang.AbstractStringBuilder类,都实现java.io.Serializable和java.lang.CharSequence接口。
最大的区别在于:<b><u>StringBuffer是线程安全的,而StringBuilder是非线程安全的</u></b>

下面代码摘自java.lang.StringBuffer

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

下面代码摘自java.lang.StringBuilder

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

AbstractStringBuilder类

AbstractStringBuilder类封装了StringBuffer和StringBuilder大部分操作的实现。

字符串的内存形态

下面代码摘自java.lang.AbstractStringBuilder

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;

    /**
     * The count is the number of characters used.
     */
    int count;

StringBuffer和StringBuilder没有具体的成员变量来存储字符串,而是使用继承自AbstractStringBuilder类的成员变量char[] value,因为没有使用final关键字修饰,因此值是可变的。

字符串构造方法

下面代码摘自java.lang.StringBuffer

public StringBuffer() {
    super(16);
}

下面代码摘自java.lang.StringBuilder

public StringBuilder() {
    super(16);
}

下面代码摘自java.lang.AbstractStringBuilder

AbstractStringBuilder(int capacity) {
    value = new char[capacity];
}

当创建一个StirngBuffer或StringBuilder对象时,若不指定容量,则默认创建长度为16的char类型数组

字符串的append操作

下面代码摘自java.lang.AbstractStringBuilder,以入参为String对象为例

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    // 检查是否char[]数组是否需要扩容
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    // value.length默认长度是16
    // minimumCapacity = str.length + 字符串的实际长度
    // 若当前字符串数组长度不足最小应分配的长度,则将重新创建一个长度的char[]数组
    if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value,
                newCapacity(minimumCapacity));
    }
}
StringBuffer.append()
StringBuffer.append()

字符串的insert操作

下面代码摘自java.lang.AbstractStringBuilder,以入参为String对象为例

public AbstractStringBuilder insert(int offset, String str) {
    if ((offset < 0) || (offset > length()))
        throw new StringIndexOutOfBoundsException(offset);
    if (str == null)
        str = "null";
    int len = str.length();
    ensureCapacityInternal(count + len);
    System.arraycopy(value, offset, value, offset + len, count - offset);
    str.getChars(value, offset);
    count += len;
    return this;
}
StringBuffer.insert
StringBuffer.insert

假设执行如下代码:

StringBuffer sb = new StringBuffer("abghij");
sb.insert(2, "cdef");
StringBuffer.insert.visio
StringBuffer.insert.visio

字符串的delete操作

下面代码摘自java.lang.AbstractStringBuilder

public AbstractStringBuilder delete(int start, int end) {
    if (start < 0)
        throw new StringIndexOutOfBoundsException(start);
    if (end > count)
        end = count;
    if (start > end)
        throw new StringIndexOutOfBoundsException();
    int len = end - start;
    if (len > 0) {
        System.arraycopy(value, start+len, value, start, count-end);
        count -= len;
    }
    return this;
}

实际上的操作是字符串数组拷贝,假设执行如下代码:

StringBuffer sb = new StringBuffer("abcdefghij");
sb.delete(2, 6);
StringBuffer.delete
StringBuffer.delete

StringBuffer类

为什么是线程安全的

线程安全是指多线程操作同一个对象,不会出现同步等问题。StringBuffer类中,使用了大量的synchronized关键字来修饰方法。
摘取java.lang.StringBuffer部分使用synchronized关键字修饰的代码

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

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

@Override
public synchronized void ensureCapacity(int minimumCapacity) {
    super.ensureCapacity(minimumCapacity);
}

transient关键字

摘自Java Language Specification, Java SE 7 Edition, Section 8.3.1.3. transient Fields

Variables may be marked transient to indicate that they are not part of the persistent state of an object.

在Java中,transient关键字用来指出哪些成员变量不应该被序列化。值得注意的是:

  • 序列化针对的是对象,而不是类;
  • static修饰的变量,本身是隐式的transient,同时静态变量是属于类层次,不能被序列化;
  • transient只能用于修饰成员变量,不能修饰本地变量,不能修饰方法和类。

StringBuffer类中,有一个成员变量

/**
 * A cache of the last value returned by toString. Cleared
 * whenever the StringBuffer is modified.
 */
private transient char[] toStringCache;

toStringCache这个成员变量,从命名上看,猜测是为了用于toString()方法而做的字符串缓冲。可见,如果是为了做缓冲,确实没必要在StringBuffer对象中持久化。

toString的操作

下面代码摘自java.lang.StringBuffer

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

toStringCache获得实际长度的字符串数组,并创建一个String对象


参考材料

Java SE java.lang.StringBuffer
Java SE java.lang.StringBuilder
Java transient关键字

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

推荐阅读更多精彩内容