StringBuilder和StringBuffer

  前面讲到String是不可变的,如果需要可变的字符串将如何使用和操作呢?JAVA提供了连个操作可变字符串的类,StringBuilder和StringBuffer,从源码中可以看到这两个类都是采用final修饰,并且继承抽象类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;
}

  同String相同,都是采用字符数组来存储的,但是String中使用final修饰,是不可变的。

  StringBuffer和StringBuilder都提供了一些常用的操作字符串的方法,有什么不同之处呢?还是从源码着手分析:

StringBuffer源码解析

/**
 * Constructs a string buffer with no characters in it and an
 * initial capacity of 16 characters.
 */
public StringBuffer() {
    super(16);
}

  看AbstractStringBuilder可知:

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

  无参构造函数,构造一个初始容量为16的字符串缓冲区。同时提供多个有参的构造函数,其中:

/**
 * Constructs a string buffer initialized to the contents of the
 * specified string. The initial capacity of the string buffer is
 * {@code 16} plus the length of the string argument.
 *
 * @param   str   the initial contents of the buffer.
 */
public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);
}

  这个构造函数需提供一个字符串参数,构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容,该字符串的初始容量为 16 加上字符串参数的长度。其中的append方法是重要部分。

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

// AbstractStringBuilder
public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}

  append方法前加了同步锁,保证了线程安全,StringBuffer中很多方法都采用同步锁,保证了多线程操作时的同步安全。

  其中的ensureCapacityInternal方法中对存储空间的分配:当存储空间不够用的时候,重新new char[],存储空间为:(原始大小+1)*2,最大为:Integer.MAX_VALUE ,

StringBuilder

  StringBuilder通StringBuffer操作逻辑基本一致,只是没有做同步处理。

总结

  String:字符常量

  StringBuffer:字符变量【线程安全】

  StringBuilder:字符变量【非线程安全】

  由此也可知,在大部分情况下,三者在执行速度方面的比较:StringBuilder > StringBuffer > String

  用法总结:

  String:用于少量需要对字符串进行操作【因为String 每次生成对象都会对系统性能产生影响,当内存中无引用对象产生过多时,GC就会开始工作】

  StringBuilder:单线程下,多次大量操作字符串【字符串处理时不会产生新的对象,而是对象自身做改变】

  StringBuffer:多线程下,多次大量操作字符串【字符串处理时不会产生新的对象,而是对象自身做改变】

源码记:苦人所不苦,能人所不能,所谓成也
声明:原创博客请在转载时保留原文链接或者在文章开头加上本人博客地址,如发现错误,欢迎批评指正。