AbstractStringBuilder source code

Introduction

The abstract class AbstractStringBuilder is the direct parent class of StringBuilder and StringBuffer, and defines many methods, so it is recommended to learn the AbstractStringBuilder abstract class before learning these two classes

This class is annotated in the source code to exist as the parent class of the first two classes starting from JDK1.5

abstract class AbstractStringBuilder implements Appendable, CharSequence

image-20230523071729335

Two interfaces are implemented, among which the interface of the character sequence CharSequence is already familiar:

This interface specifies the length of the character sequence that needs to be implemented: length();

The character whose subscript is index can be obtained: charAt(int index);

A sub-character sequence of the character sequence can be obtained: subSequence(int start, int end);

Specifies the String version of the character sequence (rewriting toString() of the parent class Object): toString();

The Appendable interface, as the name suggests, defines the ‘rules’ to add:

append(CharSequence csq) throws IOException: How to add a character sequence

append(CharSequence csq, int start, int end) throws IOException: How to add part of a character sequence

append(char c) throws IOException: how to add a character

Constants & Variables

 /**
     * The value is used for character storage.
     * The specific storage of this character sequence is not modified by final, which means that it can be continuously expanded
     */
    char[] value;

    /**
     * The count is the number of characters used.
     * Actual storage quantity
     */
    int count;
    
     /**
     * The maximum size of array to allocate (unless necessary).
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     * Maximum array length
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

Construction method

 /**
     * 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];
    }

Common methods

length()

 /**
     * Returns the length (character count).
     *
     * @return the length of the sequence of characters currently
     * represented by this object
     * Return the actual length that has been stored (that is, the count value)
     */
    @Override
    public int length() {<!-- -->
        return count;
    }

capacity()

 /**
     * 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
     * Get the actual size of the current value array
     */
    public int capacity() {<!-- -->
        return value. length;
    }

ensureCapacity

 /**
     *Ensures that the capacity is at least equal to the specified minimum.
     * If the current capacity is less than the argument, then a new internal
     * array is allocated with greater capacity. The new capacity is the
     * larger of:
     * <ul>
     * <li>The {@code minimumCapacity} argument.
     * <li>Twice the old capacity, plus {@code 2}.
     *</ul>
     * If the {@code minimumCapacity} argument is nonpositive, this
     * method takes no action and simply returns.
     * Note that subsequent operations on this object can reduce the
     * actual capacity below that requested here.
     *
     * @param minimumCapacity the minimum desired capacity.
     * Make sure the capacity is at least equal to the specified minimum. If the current capacity is less than the argument, allocate a new array with a greater capacity
     *
     */
    public void ensureCapacity(int minimumCapacity) {<!-- -->
        if (minimumCapacity > 0)
            ensureCapacityInternal(minimumCapacity);
    }

    /**
     * For positive values of {@code minimumCapacity}, this method
     * behaves like {@code ensureCapacity}, however it is never
     * synchronized.
     * If {@code minimumCapacity} is non positive due to numeric
     * overflow, this method throws {@code OutOfMemoryError}.
     */
    private void ensureCapacityInternal(int minimumCapacity) {<!-- -->
        // overflow-conscious code
        // Implementation of expansion
        if (minimumCapacity - value. length > 0) {<!-- -->
           //Copy a new array of minimumCapacity size
            value = Arrays. copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }
    
     /**
     * Returns a capacity at least as large as the given minimum capacity.
     * Returns the current capacity increased by the same amount + 2 if
     * that suffices.
     * Will not return a capacity greater than {@code MAX_ARRAY_SIZE}
     * unless the given minimum capacity is greater than that.
     *
     * @param minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if minCapacity is less than zero or
     * greater than Integer.MAX_VALUE
     */
    private int newCapacity(int minCapacity) {<!-- -->
        // overflow-conscious code
        //The capacity of the new array
        int newCapacity = (value. length << 1) + 2;
        //If the expanded array capacity is still smaller than the specified capacity
        if (newCapacity - minCapacity < 0) {<!-- -->
            //The capacity of the new array is equal to the specified capacity of Diehl
            newCapacity = minCapacity;
        }
        //judgment boundary value
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            // out of bounds
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

    private int hugeCapacity(int minCapacity) {<!-- -->
        // exceed the maximum value, report an error
        if (Integer.MAX_VALUE - minCapacity < 0) {<!-- --> // overflow
            throw new OutOfMemoryError();
        }
        // Determine the capacity of the new array again
        return (minCapacity > MAX_ARRAY_SIZE)
            ? minCapacity : MAX_ARRAY_SIZE;
    }

trimToSize

 /**
     * Attempts to reduce storage used for the character sequence.
     * If the buffer is larger than necessary to hold its current sequence of
     * characters, then it may be resized to become more space efficient.
     * Calling this method may, but is not required to, affect the value
     * returned by a subsequent call to the {@link #capacity()} method.
     * If the capacity of the value array is redundant, then release all the excess
     */
    public void trimToSize() {<!-- -->
        //The length of the array is greater than the number currently stored
        if (count < value. length) {<!-- -->
            //Copy a new array of count size
            value = Arrays. copyOf(value, count);
        }
    }

setLength

 /**
     * Sets the length of the character sequence.
     * The sequence is changed to a new character sequence
     * whose length is specified by the argument. For every nonnegative
     * index <i>k</i> less than {@code newLength}, the character at
     * index <i>k</i> in the new character sequence is the same as the
     * character at index <i>k</i> in the old sequence if <i>k</i> is less
     * than the length of the old character sequence; otherwise, it is the
     * null character {@code '\u0000'}.
     *
     * In other words, if the {@code newLength} argument is less than
     * the current length, the length is changed to the specified length.
     * <p>
     * If the {@code newLength} argument is greater than or equal
     * to the current length, sufficient null characters
     * ({@code '\u0000'}) are appended so that
     * length becomes the {@code newLength} argument.
     * <p>
     * The {@code newLength} argument must be greater than or equal
     * to {@code 0}.
     *
     * @param newLength the new length
     * @throws IndexOutOfBoundsException if the
     * {@code newLength} argument is negative.
     * Forcibly increase the size of the actual length count, if the capacity is not enough, use expandCapacity() to expand;
     * Initialize the expanded part with '\0' (null in ASCII code)
     */
    public void setLength(int newLength) {<!-- -->
        if (newLength < 0)
            throw new StringIndexOutOfBoundsException(newLength);
        //Determine whether to expand
        ensureCapacityInternal(newLength);

        if (count < newLength) {<!-- -->
            // fill the array
            Arrays.fill(value, count, newLength, '\0');
        }

        count = newLength;
    }

charAt

 /**
     * Returns the {@code char} value in this sequence at the specified index.
     * The first {@code char} value is at index {@code 0}, the next at index
     * {@code 1}, and so on, as in array indexing.
     * <p>
     * The index argument must be greater than or equal to
     * {@code 0}, and less than the length of this sequence.
     *
     * <p>If the {@code char} value specified by the index is a
     * <a href="Character.html#unicode">surrogate</a>, the surrogate
     * value is returned.
     *
     * @param index the index of the desired {@code char} value.
     * @return the {@code char} value at the specified index.
     * @throws IndexOutOfBoundsException if {@code index} is
     * negative or greater than or equal to {@code length()}.
     * Get the character whose subscript is index
     */
    @Override
    public char charAt(int index) {<!-- -->
        if ((index < 0) || (index >= count))
            throw new StringIndexOutOfBoundsException(index);
        return value[index];
    }

codePointAt

 /**
     * Returns the character (Unicode code point) at the specified
     * index. The index refers to {@code char} values
     * (Unicode code units) and ranges from {@code 0} to
     * {@link #length()}{@code - 1}.
     *
     * <p> If the {@code char} value specified at the given index
     * is in the high-surrogate range, the following index is less
     * than the length of this sequence, and the
     * {@code char} value at the following index is in the
     * low-surrogate range, then the supplementary code point
     * corresponding to this surrogate pair is returned. Otherwise,
     * the {@code char} value at the given index is returned.
     *
     * @param index the index to the {@code char} values
     * @return the code point value of the character at the
     * {@code index}
     * @exception IndexOutOfBoundsException if the {@code index}
     * argument is negative or not less than the length of this
     * sequence.
     * Returns the character at the specified index (Unicode code point)
     */
    public int codePointAt(int index) {<!-- -->
        if ((index < 0) || (index >= count)) {<!-- -->
            throw new StringIndexOutOfBoundsException(index);
        }
        return Character.codePointAtImpl(value, index, count);
    }

getChars

 /**
     * Characters are copied from this sequence into the
     * destination character array {@code dst}. The first character to
     * be copied is at index {@code srcBegin}; the last character to
     * be copied is at index {@code srcEnd-1}. The total number of
     * characters to be copied is {@code srcEnd-srcBegin}. The
     * characters are copied into the subarray of {@code dst} starting
     * at index {@code dstBegin} and ending at index:
     * <pre>{@code
     * dstbegin + (srcEnd-srcBegin) - 1
     * }

*
* @param srcBegin start copying at this offset.
* @param srcEnd stop copying at this offset.
* @param dst the array to copy the data into.
* @param dstBegin offset into {@code dst}.
* @throws IndexOutOfBoundsException if any of the following is true:
*

    *

  • {@code srcBegin} is negative
    *

  • {@code dstBegin} is negative
    *

  • the {@code srcBegin} argument is greater than
    * the {@code srcEnd} argument.
    *

  • {@code srcEnd} is greater than
    * {@code this. length()}.
    *

  • {@code dstBegin + srcEnd-srcBegin} is greater than
    * {@code dst. length}
    *

* Copy [srcBegin, srcEnd) of value[] to the beginning of desBegin of dst[] array
*/
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
{
if (srcBegin < 0) throw new StringIndexOutOfBoundsException(srcBegin); if ((srcEnd < 0) || (srcEnd > count))
throw new StringIndexOutOfBoundsException(srcEnd);
if (srcBegin > srcEnd)
throw new StringIndexOutOfBoundsException(“srcBegin > srcEnd”);
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd – srcBegin);
}

substring

 /**
     * Returns a new {@code String} that contains a subsequence of
     * characters currently contained in this character sequence. The
     * substring begins at the specified index and extends to the end of
     * this sequence.
     *
     * @param start The beginning index, inclusive.
     * @return The new string.
     * @throws StringIndexOutOfBoundsException if {@code start} is
     * less than zero, or greater than the length of this object.
     * get substring
     */
    public String substring(int start) {<!-- -->
        return substring(start, count);
    }
    
     /**
     * Returns a new {@code String} that contains a subsequence of
     * characters currently contained in this sequence. The
     * substring begins at the specified {@code start} and
     * extends to the character at index {@code end - 1}.
     *
     * @param start The beginning index, inclusive.
     * @param end The ending index, exclusive.
     * @return The new string.
     * @throws StringIndexOutOfBoundsException if {@code start}
     * or {@code end} are negative or greater than
     * {@code length()}, or {@code start} is
     * greater than {@code end}.
     */
    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);
    }

subSequence

 /**
     * Returns a new character sequence that is a subsequence of this sequence.
     *
     * <p> An invocation of this method of the form
     *
     * <pre>{@code
     * sb.subSequence(begin, &nbsp;end)}

*
* behaves in exactly the same way as the invocation
*
*

{@code
     * sb.substring(begin, &nbsp;end)}

*
* This method is provided so that this class can
* implement the {@link CharSequence} interface.
*
* @param start the start index, inclusive.
* @param end the end index, exclusive.
* @return the specified subsequence.
*
* @throws IndexOutOfBoundsException
* if {@code start} or {@code end} are negative,
* if {@code end} is greater than {@code length()},
* or if {@code start} is greater than {@code end}
* @spec JSR-51
* get a sequence of subcharacters
*/
@Override
public CharSequence subSequence(int start, int end) {
return substring(start, end);
}

reverse

 /**
     * Causes this character sequence to be replaced by the reverse of
     * the sequence. If there are any surrogate pairs included in the
     * sequence, these are treated as single characters for the
     * reverse operation. Thus, the order of the high-low surrogates
     * is never reversed.
     *
     * Let <i>n</i> be the character length of this character sequence
     * (not the length in {@code char} values) just prior to
     * execution of the {@code reverse} method. Then the
     * character at index <i>k</i> in the new character sequence is
     * equal to the character at index <i>n-k-1</i> in the old
     * character sequence.
     *
     * <p>Note that the reverse operation may result in producing
     * surrogate pairs that were unpaired low-surrogates and
     * high-surrogates before the operation. For example, reversing
     * "\uDC00\uD800" produces "\uD800\uDC00" which is
     * a valid surrogate pair.
     *
     * @return a reference to this object.
     * Store the value in reverse order
     * (Note that the value is changed instead of creating a new AbstractStringBuilder and the value is in reverse order)
     */
    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;
    }

github:AbstractStringBuilder source code

Please leave a message if you have any questions about the article, thank you~