1. 程式人生 > >Java中String、StringBuilder、StringBuffer常用源碼分析及比較(二):StringBuilder、StringBuffer源碼分析

Java中String、StringBuilder、StringBuffer常用源碼分析及比較(二):StringBuilder、StringBuffer源碼分析

string類型 character private 字符 代碼 less pri des over

StringBuilder:

一、構造方法:

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

    /**
     * Constructs a string builder with no characters in it and an
     * initial capacity specified by the <code>capacity</code> argument.
     *
     * 
@param capacity the initial capacity. * @throws NegativeArraySizeException if the <code>capacity</code> * argument is less than <code>0</code>. */ public StringBuilder(int capacity) { super(capacity); } /** * Constructs a string builder initialized to the contents of the * specified string. The initial capacity of the string builder is * <code>16</code> plus the length of the string argument. * *
@param str the initial contents of the buffer. * @throws NullPointerException if <code>str</code> is <code>null</code> */ public StringBuilder(String str) { super(str.length() + 16); append(str); } /** * Constructs a string builder that contains the same characters * as the specified <code>CharSequence</code>. The initial capacity of * the string builder is <code>16</code> plus the length of the * <code>CharSequence</code> argument. * *
@param seq the sequence to copy. * @throws NullPointerException if <code>seq</code> is <code>null</code> */ public StringBuilder(CharSequence seq) { this(seq.length() + 16); append(seq); }

從代碼可知,StringBuilder的不管哪個構造方法,都用到了父類AbstractStringBuilder的構造方法,那麽來看一下它的父類AbstractStringBuilder。

成員變量+構造方法:

/**
     * The value is used for character storage.
     */
    char[] value;

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

    /**
     * This no-arg constructor is necessary for serialization of subclasses.
     */
    AbstractStringBuilder() {
    }

    /**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

從該父類就可以看出,StringBuilder與String一樣是通過char數組value來存字符串,但不一樣的是這個value數組沒有用final修飾,這也是StringBuilder可以直接通過改變value做字符串拼接的原因。StringBuilder可以直接通過構造方法直接初始化value容量大小,值得註意的是,AbstractStringBuilder類擁有一個變量count,用來表示char數組中字符串真實長度,故以下兩個方法,length方法返回的是該StringBuilder中字符串的真實長度,capacity方法返回的是value數組的容量。

/**
     * Returns the length (character count).
     *
     * @return  the length of the sequence of characters currently
     *          represented by this object
     */
    public int length() {
        return count;
    }

    /**
     * Returns the current capacity. The capacity is the amount of storage
     * available for newly inserted characters, beyond which an allocation
     * will occur.
     *
     * @return  the current capacity
     */
    public int capacity() {
        return value.length;
    }

成員方法:

append方法:

public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

    // Appends the specified string builder to this sequence.
    private StringBuilder append(StringBuilder sb) {
        if (sb == null)
            return append("null");
        int len = sb.length();
        int newcount = count + len;
        if (newcount > value.length)
            expandCapacity(newcount);
        sb.getChars(0, len, value, count);
        count = newcount;
        return this;
    }

    /**
     * Appends the specified <tt>StringBuffer</tt> to this sequence.
     * <p>
     * The characters of the <tt>StringBuffer</tt> argument are appended,
     * in order, to this sequence, increasing the
     * length of this sequence by the length of the argument.
     * If <tt>sb</tt> is <tt>null</tt>, then the four characters
     * <tt>"null"</tt> are appended to this sequence.
     * <p>
     * Let <i>n</i> be the length of this character sequence just prior to
     * execution of the <tt>append</tt> 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</code>.
     *
     * @param   sb   the <tt>StringBuffer</tt> to append.
     * @return  a reference to this object.
     */
    public StringBuilder append(StringBuffer sb) {
        super.append(sb);
        return this;
    }

    /**
     */
    public StringBuilder append(CharSequence s) {
        if (s == null)
            s = "null";
        if (s instanceof String)
            return this.append((String)s);
        if (s instanceof StringBuffer)
            return this.append((StringBuffer)s);
        if (s instanceof StringBuilder)
            return this.append((StringBuilder)s);
        return this.append(s, 0, s.length());
    }

    /**
     * @throws     IndexOutOfBoundsException {@inheritDoc}
     */
    public StringBuilder append(CharSequence s, int start, int end) {
        super.append(s, start, end);
        return this;
    }

    public StringBuilder append(char[] str) {
        super.append(str);
        return this;
    }

    /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public StringBuilder append(char[] str, int offset, int len) {
        super.append(str, offset, len);
        return this;
    }

    public StringBuilder append(boolean b) {
        super.append(b);
        return this;
    }

    public StringBuilder append(char c) {
        super.append(c);
        return this;
    }

    public StringBuilder append(int i) {
        super.append(i);
        return this;
    }

    public StringBuilder append(long lng) {
        super.append(lng);
        return this;
    }

    public StringBuilder append(float f) {
        super.append(f);
        return this;
    }

    public StringBuilder append(double d) {
        super.append(d);
        return this;
    }

可以看出StringBuilder的append方法還是來自它的父類AbstractStringBuilder,直接貼上父類append,只列出幾個常用的

/**
     * Appends the string representation of the {@code Object} argument.
     * <p>
     * The overall effect is exactly as if the argument were converted
     * to a string by the method {@link String#valueOf(Object)},
     * and the characters of that string were then
     * {@link #append(String) appended} to this character sequence.
     *
     * @param   obj   an {@code Object}.
     * @return  a reference to this object.
     */
    public AbstractStringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }

    /**
     * Appends the specified string to this character sequence.
     * <p>
     * The characters of the {@code String} argument are appended, in
     * order, increasing the length of this sequence by the length of the
     * argument. If {@code str} is {@code null}, then the four
     * characters {@code "null"} are appended.
     * <p>
     * Let <i>n</i> be the length of this character sequence 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 str}.
     *
     * @param   str   a string.
     * @return  a reference to this object.
     */
    public AbstractStringBuilder append(String str) {
        if (str == null) str = "null";
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

    // Documentation in subclasses because of synchro difference
    public AbstractStringBuilder append(StringBuffer sb) {
        if (sb == null)
            return append("null");
        int len = sb.length();
        ensureCapacityInternal(count + len);
        sb.getChars(0, len, value, count);
        count += len;
        return this;
    }

通過可以看出以上代碼看出兩點:1.append對傳入的參數進行了判空,且為空是將字符串“null”拼接了進去,與String類型的‘+’拼接null字符串一樣

2.如果values的容量大小不足以裝下拼接後的字符串,會重建一個value,並將之前的value復制進去,具體反映在:

/**
     * This method has the same contract as ensureCapacity, but is
     * never synchronized.
     */
    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0)
            expandCapacity(minimumCapacity);
    }

/**
     * This implements the expansion semantics of ensureCapacity with no
     * size check or synchronization.
     */
    void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
    }

public static char[] copyOf(char[] original, int newLength) {
        char[] copy = new char[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

StringBuffer:

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

通過StringBuffer類的定義及構造方法,我們可以看到其實和StringBuilder非常類似甚至完全一樣,不必多說,StringBuffer也是通過char數組value

來存字符串,且一樣是沒有final修飾。

append方法:

public synchronized StringBuffer append(Object obj) {
        super.append(String.valueOf(obj));
        return this;
    }

    public synchronized StringBuffer append(String str) {
        super.append(str);
        return this;
    }

    /**
     * Appends the specified <tt>StringBuffer</tt> to this sequence.
     * <p>
     * The characters of the <tt>StringBuffer</tt> argument are appended,
     * in order, to the contents of this <tt>StringBuffer</tt>, increasing the
     * length of this <tt>StringBuffer</tt> by the length of the argument.
     * If <tt>sb</tt> is <tt>null</tt>, then the four characters
     * <tt>"null"</tt> are appended to this <tt>StringBuffer</tt>.
     * <p>
     * Let <i>n</i> be the length of the old character sequence, the one
     * contained in the <tt>StringBuffer</tt> just prior to execution of the
     * <tt>append</tt> 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</code>.
     * <p>
     * This method synchronizes on <code>this</code> (the destination)
     * object but does not synchronize on the source (<code>sb</code>).
     *
     * @param   sb   the <tt>StringBuffer</tt> to append.
     * @return  a reference to this object.
     * @since 1.4
     */
    public synchronized StringBuffer append(StringBuffer sb) {
        super.append(sb);
        return this;
    }

可以看到與StringBuilder唯一不同的是每個append方法都加了synchronized修飾,即鎖(不允許多線程同時訪問),這也是StringBuffer是線程安全的,StringBuilder是線程不安全的原因

Java中String、StringBuilder、StringBuffer常用源碼分析及比較(二):StringBuilder、StringBuffer源碼分析