当前位置:首页 > 分类 > JAVA基础 > JDK源码-StringBuffer和StringBuilder的区别

JDK源码-StringBuffer和StringBuilder的区别


类定义 

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

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

说起StringBuffer,StringBuilder就不得不说AbstractStringBuilder了,两个类都是继承这个抽象类。

两个类定义完全相同,都是不能继承的final类。


构造器定义

 /**
    * Constructs a string buffer with no characters in it and an
    * initial capacity of 16 characters.
    */
   public StringBuffer() {
       super(16);
   }
    AbstractStringBuilder(int capacity) {
       value = new char[capacity];
   }

默认构造长度16的字符数组。


属性定义 

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;
    ……
    ……
 }

都是使用的AbstractStringBuilder类的属性。

String类的final属性不同的是,它们的属性都是可修改的,并提供了修改的方法。


但StringBuffer新增了一个不参与序列化的属性toStringCache,解释为toString方法返回最后一次修改值的缓存。每当修改StringBuffer时清除。

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


方法定义 

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

上面两个方法,看方法返回值可确定所属类。

方法虽有重写,但方法里面都是用的super.xxx(),也就是都是使用的AbstractStringBuilder类的方法。

方法都是返回的this,换句话说,操作都是在原实例上进行,没有创建新实例。

区别在于StringBuffer的所有public方法都使用了synchronized关键字,牺牲性能来保证线程安全。


上面toStringCache属性说到toString方法,这里看下。

     //StringBuffer 
    @Override
   public synchronized String toString() {
       if (toStringCache == null) {
           toStringCache = Arrays.copyOfRange(value, 0, count);
       }
       return new String(toStringCache, true);
   }
   
   //StringBuilder
    @Override
   public String toString() {
       // Create a copy, don't share the array
       return new String(value, 0, count);
   }


可见tostring都是用StringBuffer或StringBuilder原实例的value属性构建新的string实例。

上面StringBuffer的append方法可见toStringCache=null;也就是上面属性定义说的,每当修改StringBuffer时清除。

上面StringBuffer的toString方法可见toStringCache = Arrays.copyOfRange(value, 0, count);也就是上面属性定义说的,toString方法返回最后一次修改值的缓存。也只有调用toString方法是才会生成缓存。



方法内部

append

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;
    }
     public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }

insert

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

delete

 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;
    }

replace

public AbstractStringBuilder replace(int start, int end, String str) {
       if (start < 0)
           throw new StringIndexOutOfBoundsException(start);
       if (start > count)
           throw new StringIndexOutOfBoundsException("start > length()");
       if (start > end)
           throw new StringIndexOutOfBoundsException("start > end");

       if (end > count)
           end = count;
       int len = str.length();
       int newCount = count + len - (end - start);
       ensureCapacityInternal(newCount);

       System.arraycopy(value, end, value, start + len, count - end);
       str.getChars(value, start);
       count = newCount;
       return this;
   }

可见都是使用的System.arraycopy方法。


substring

public String substring(int start, int end) {
       if (start < 0)
           throw new StringIndexOutOfBoundsException(start);
       if (end > count)
           throw new StringIndexOutOfBoundsException(end);
       if (start > end)
           throw new StringIndexOutOfBoundsException(end - start);
       return new String(value, start, end - start);
   }

返回新的被切割的字符串。


reverse

public AbstractStringBuilder reverse() {
       boolean hasSurrogates = false;
       int n = count - 1;
       for (int j = (n-1) >> 1; j >= 0; j--) {
           int k = n - j;
           char cj = value[j];
           char ck = value[k];
           value[j] = ck;
           value[k] = cj;
           if (Character.isSurrogate(cj) ||
               Character.isSurrogate(ck)) {
               hasSurrogates = true;
           }
       }
       if (hasSurrogates) {
           reverseAllValidSurrogatePairs();
       }
       return this;
   }

把字符数组的字符位置互换了。

常见的面试题,字符串倒序处理

String youfengxin = "youfengxin.com";
System.out.println(new StringBuilder(youfengxin).reverse().toString());