• Java源码学习 -- java.lang.StringBuilder,java.lang.StringBuffer,java.lang.AbstractStringBuilder


    一直以来,都是看到网上说“ StringBuilder是线程不安全的,但运行效率高;StringBuffer 是线程安全的,但运行效率低”,然后默默记住:一个是线程安全、一个线程不安全,但对内在原因并不了解。这两天终于下定决心看了下源代码,才深刻理解为啥一个线程安全、一个非线程安全。

    一名话总结:java.lang.StringBuilder 与 java.lang.StringBuffer 同是继承于 java.lang.AbstractStringBuilder,具体在功能实现大多在 AbstractStringBuilder 中,StringBuilder 和 StringBuffer 相当于对其进行的一个接口封装,区别只是一个作了同步封装、一个作非同步封装。

    由表及里,首先从 StringBuilder 和 StringBuffer 源代码中的构造方法和 append,delete,replace,insert,toString 等方法研究起。

    java.lang.StringBuilder

    StringBuilder 是一个 final 类,不能被继承。其类继承父类和实现的接口关系如下所示:

    1 public final class StringBuilder
    2     extends AbstractStringBuilder
    3     implements java.io.Serializable, CharSequence
    4 {}

    其内部代码中显式声明(不包括继承等隐式属性)的只有一个属性:serialVersionUID(序列化ID)。其构造方法的内部实现也是通过 super 方法调用父类构造方法实现,具体如下所示:

     1     /**
     2      * Constructs a string builder with no characters in it and an
     3      * initial capacity of 16 characters.
     4      */
     5     public StringBuilder() {
     6         super(16);
     7     }
     8 
     9     /**
    10      * Constructs a string builder with no characters in it and an
    11      * initial capacity specified by the <code>capacity</code> argument.
    12      *
    13      * @param      capacity  the initial capacity.
    14      * @throws     NegativeArraySizeException  if the <code>capacity</code>
    15      *               argument is less than <code>0</code>.
    16      */
    17     public StringBuilder(int capacity) {
    18         super(capacity);
    19     }
    20 
    21     /**
    22      * Constructs a string builder initialized to the contents of the
    23      * specified string. The initial capacity of the string builder is
    24      * <code>16</code> plus the length of the string argument.
    25      *
    26      * @param   str   the initial contents of the buffer.
    27      * @throws    NullPointerException if <code>str</code> is <code>null</code>
    28      */
    29     public StringBuilder(String str) {
    30         super(str.length() + 16);
    31         append(str);
    32     }
    33 
    34     /**
    35      * Constructs a string builder that contains the same characters
    36      * as the specified <code>CharSequence</code>. The initial capacity of
    37      * the string builder is <code>16</code> plus the length of the
    38      * <code>CharSequence</code> argument.
    39      *
    40      * @param      seq   the sequence to copy.
    41      * @throws    NullPointerException if <code>seq</code> is <code>null</code>
    42      */
    43     public StringBuilder(CharSequence seq) {
    44         this(seq.length() + 16);
    45         append(seq);
    46     }
    View Code

    append 方法

    仅以一个 append 方法为例具体看看其内部实现,代码如下:

    1     public StringBuilder append(String str) {
    2         super.append(str);
    3         return this;
    4     }

    在该方法内部仍然是一个 super 方法,调用父类在方法实现,只是做了一层外壳。其它的 delete,replace,insert 方法源代码也是如此,这里就不一一展示了。相关的 append 重载方法源码如下所示:

      1     public StringBuilder append(Object obj) {
      2         return append(String.valueOf(obj));
      3     }
      4 
      5     public StringBuilder append(String str) {
      6         super.append(str);
      7         return this;
      8     }
      9 
     10     // Appends the specified string builder to this sequence.
     11     private StringBuilder append(StringBuilder sb) {
     12         if (sb == null)
     13             return append("null");
     14         int len = sb.length();
     15         int newcount = count + len;
     16         if (newcount > value.length)
     17             expandCapacity(newcount);
     18         sb.getChars(0, len, value, count);
     19         count = newcount;
     20         return this;
     21     }
     22 
     23     /**
     24      * Appends the specified <tt>StringBuffer</tt> to this sequence.
     25      * <p>
     26      * The characters of the <tt>StringBuffer</tt> argument are appended,
     27      * in order, to this sequence, increasing the
     28      * length of this sequence by the length of the argument.
     29      * If <tt>sb</tt> is <tt>null</tt>, then the four characters
     30      * <tt>"null"</tt> are appended to this sequence.
     31      * <p>
     32      * Let <i>n</i> be the length of this character sequence just prior to
     33      * execution of the <tt>append</tt> method. Then the character at index
     34      * <i>k</i> in the new character sequence is equal to the character at
     35      * index <i>k</i> in the old character sequence, if <i>k</i> is less than
     36      * <i>n</i>; otherwise, it is equal to the character at index <i>k-n</i>
     37      * in the argument <code>sb</code>.
     38      *
     39      * @param   sb   the <tt>StringBuffer</tt> to append.
     40      * @return  a reference to this object.
     41      */
     42     public StringBuilder append(StringBuffer sb) {
     43         super.append(sb);
     44         return this;
     45     }
     46 
     47     /**
     48      */
     49     public StringBuilder append(CharSequence s) {
     50         if (s == null)
     51             s = "null";
     52         if (s instanceof String)
     53             return this.append((String)s);
     54         if (s instanceof StringBuffer)
     55             return this.append((StringBuffer)s);
     56         if (s instanceof StringBuilder)
     57             return this.append((StringBuilder)s);
     58         return this.append(s, 0, s.length());
     59     }
     60 
     61     /**
     62      * @throws     IndexOutOfBoundsException {@inheritDoc}
     63      */
     64     public StringBuilder append(CharSequence s, int start, int end) {
     65         super.append(s, start, end);
     66         return this;
     67     }
     68 
     69     public StringBuilder append(char[] str) {
     70         super.append(str);
     71         return this;
     72     }
     73 
     74     /**
     75      * @throws IndexOutOfBoundsException {@inheritDoc}
     76      */
     77     public StringBuilder append(char[] str, int offset, int len) {
     78         super.append(str, offset, len);
     79         return this;
     80     }
     81 
     82     public StringBuilder append(boolean b) {
     83         super.append(b);
     84         return this;
     85     }
     86 
     87     public StringBuilder append(char c) {
     88         super.append(c);
     89         return this;
     90     }
     91 
     92     public StringBuilder append(int i) {
     93         super.append(i);
     94         return this;
     95     }
     96 
     97     public StringBuilder append(long lng) {
     98         super.append(lng);
     99         return this;
    100     }
    101 
    102     public StringBuilder append(float f) {
    103         super.append(f);
    104         return this;
    105     }
    106 
    107     public StringBuilder append(double d) {
    108         super.append(d);
    109         return this;
    110     }
    View Code

    toString 方法

    与 append,delete,replace,insert等方法不同的是,toString 方法不是通过 super 方法调用父类的实现。但其实现中所用到的 value,count 属性依然是从父类中继承的,其实现仍然很简单,如下所示:

    1     public String toString() {
    2         // Create a copy, don't share the array
    3         return new String(value, 0, count);
    4     }

    java.lang.StringBuffer

    当认识了 java.lang.StringBuilder 后,再来学习 StringBuffer 就相当简单了。其类声明和构造方法与 StringBuilder 完全一样。各功能方法内部实现上也完全一样,具体实现调用 super 方法通过父类实现。唯一的不同之处便是:功能方法前面多了一个同步关键字 synchronized。这里只简单给出其部分源代码,以供参考。

    类声明和构造方法源码如下:

     1  public final class StringBuffer
     2     extends AbstractStringBuilder
     3     implements java.io.Serializable, CharSequence
     4 {
     5 
     6     /** use serialVersionUID from JDK 1.0.2 for interoperability */
     7     static final long serialVersionUID = 3388685877147921107L;
     8 
     9     /**
    10      * Constructs a string buffer with no characters in it and an
    11      * initial capacity of 16 characters.
    12      */
    13     public StringBuffer() {
    14         super(16);
    15     }
    16 
    17     /**
    18      * Constructs a string buffer with no characters in it and
    19      * the specified initial capacity.
    20      *
    21      * @param      capacity  the initial capacity.
    22      * @exception  NegativeArraySizeException  if the <code>capacity</code>
    23      *               argument is less than <code>0</code>.
    24      */
    25     public StringBuffer(int capacity) {
    26         super(capacity);
    27     }
    28 
    29     /**
    30      * Constructs a string buffer initialized to the contents of the
    31      * specified string. The initial capacity of the string buffer is
    32      * <code>16</code> plus the length of the string argument.
    33      *
    34      * @param   str   the initial contents of the buffer.
    35      * @exception NullPointerException if <code>str</code> is <code>null</code>
    36      */
    37     public StringBuffer(String str) {
    38         super(str.length() + 16);
    39         append(str);
    40     }
    41 
    42     /**
    43      * Constructs a string buffer that contains the same characters
    44      * as the specified <code>CharSequence</code>. The initial capacity of
    45      * the string buffer is <code>16</code> plus the length of the
    46      * <code>CharSequence</code> argument.
    47      * <p>
    48      * If the length of the specified <code>CharSequence</code> is
    49      * less than or equal to zero, then an empty buffer of capacity
    50      * <code>16</code> is returned.
    51      *
    52      * @param      seq   the sequence to copy.
    53      * @exception NullPointerException if <code>seq</code> is <code>null</code>
    54      * @since 1.5
    55      */
    56     public StringBuffer(CharSequence seq) {
    57         this(seq.length() + 16);
    58         append(seq);
    59     }
    60 }
    View Code

    append 功能方法源码如下:

      1     public synchronized StringBuffer append(Object obj) {
      2         super.append(String.valueOf(obj));
      3         return this;
      4     }
      5 
      6     public synchronized StringBuffer append(String str) {
      7         super.append(str);
      8         return this;
      9     }
     10 
     11     /**
     12      * Appends the specified <tt>StringBuffer</tt> to this sequence.
     13      * <p>
     14      * The characters of the <tt>StringBuffer</tt> argument are appended,
     15      * in order, to the contents of this <tt>StringBuffer</tt>, increasing the
     16      * length of this <tt>StringBuffer</tt> by the length of the argument.
     17      * If <tt>sb</tt> is <tt>null</tt>, then the four characters
     18      * <tt>"null"</tt> are appended to this <tt>StringBuffer</tt>.
     19      * <p>
     20      * Let <i>n</i> be the length of the old character sequence, the one
     21      * contained in the <tt>StringBuffer</tt> just prior to execution of the
     22      * <tt>append</tt> method. Then the character at index <i>k</i> in
     23      * the new character sequence is equal to the character at index <i>k</i>
     24      * in the old character sequence, if <i>k</i> is less than <i>n</i>;
     25      * otherwise, it is equal to the character at index <i>k-n</i> in the
     26      * argument <code>sb</code>.
     27      * <p>
     28      * This method synchronizes on <code>this</code> (the destination)
     29      * object but does not synchronize on the source (<code>sb</code>).
     30      *
     31      * @param   sb   the <tt>StringBuffer</tt> to append.
     32      * @return  a reference to this object.
     33      * @since 1.4
     34      */
     35     public synchronized StringBuffer append(StringBuffer sb) {
     36         super.append(sb);
     37         return this;
     38     }
     39 
     40 
     41     /**
     42      * Appends the specified <code>CharSequence</code> to this
     43      * sequence.
     44      * <p>
     45      * The characters of the <code>CharSequence</code> argument are appended,
     46      * in order, increasing the length of this sequence by the length of the
     47      * argument.
     48      *
     49      * <p>The result of this method is exactly the same as if it were an
     50      * invocation of this.append(s, 0, s.length());
     51      *
     52      * <p>This method synchronizes on this (the destination)
     53      * object but does not synchronize on the source (<code>s</code>).
     54      *
     55      * <p>If <code>s</code> is <code>null</code>, then the four characters
     56      * <code>"null"</code> are appended.
     57      *
     58      * @param   s the <code>CharSequence</code> to append.
     59      * @return  a reference to this object.
     60      * @since 1.5
     61      */
     62     public StringBuffer append(CharSequence s) {
     63         // Note, synchronization achieved via other invocations
     64         if (s == null)
     65             s = "null";
     66         if (s instanceof String)
     67             return this.append((String)s);
     68         if (s instanceof StringBuffer)
     69             return this.append((StringBuffer)s);
     70         return this.append(s, 0, s.length());
     71     }
     72 
     73     /**
     74      * @throws IndexOutOfBoundsException {@inheritDoc}
     75      * @since      1.5
     76      */
     77     public synchronized StringBuffer append(CharSequence s, int start, int end)
     78     {
     79         super.append(s, start, end);
     80         return this;
     81     }
     82 
     83     public synchronized StringBuffer append(char[] str) {
     84         super.append(str);
     85         return this;
     86     }
     87 
     88     /**
     89      * @throws IndexOutOfBoundsException {@inheritDoc}
     90      */
     91     public synchronized StringBuffer append(char[] str, int offset, int len) {
     92         super.append(str, offset, len);
     93         return this;
     94     }
     95 
     96     public synchronized StringBuffer append(boolean b) {
     97         super.append(b);
     98         return this;
     99     }
    100 
    101     public synchronized StringBuffer append(char c) {
    102         super.append(c);
    103         return this;
    104     }
    105 
    106     public synchronized StringBuffer append(int i) {
    107         super.append(i);
    108         return this;
    109     }
    110 
    111     /**
    112      * @since 1.5
    113      */
    114     public synchronized StringBuffer appendCodePoint(int codePoint) {
    115         super.appendCodePoint(codePoint);
    116         return this;
    117     }
    118 
    119     public synchronized StringBuffer append(long lng) {
    120         super.append(lng);
    121         return this;
    122     }
    123 
    124     public synchronized StringBuffer append(float f) {
    125         super.append(f);
    126         return this;
    127     }
    128 
    129     public synchronized StringBuffer append(double d) {
    130         super.append(d);
    131         return this;
    132     }
    View Code

    java.lang.AbstractStringBuilder

    StringBuilder,StringBuffer 均是继承于 AbstractStringBuilder ,而其方法具体实现均是调用父类的方法完成。则从功能实现上,AbstractStringBuilder 是核心。下面来研究其源码实现。

    与 java.lang.String 类似,其底层仍是通过字符数组实现字符串的存储。不同的是多了一个 count 参数,以用于记录实际存储的字符个数,而不是字符数组 value 的长度。类声明、属性及构造方法源码如下:

     1 abstract class AbstractStringBuilder implements Appendable, CharSequence {
     2     /**
     3      * The value is used for character storage.
     4      */
     5     char[] value;
     6 
     7     /**
     8      * The count is the number of characters used.
     9      */
    10     int count;
    11 
    12     /**
    13      * This no-arg constructor is necessary for serialization of subclasses.
    14      */
    15     AbstractStringBuilder() {
    16     }
    17 
    18     /**
    19      * Creates an AbstractStringBuilder of the specified capacity.
    20      */
    21     AbstractStringBuilder(int capacity) {
    22         value = new char[capacity];
    23     }
    24 }

    与 java.lang.String 相比,同是字符数组存储字符串,但 String 中声明的字符数组是 final 类型表示不可修改,而 AbstractStringBuilder 中则可以修改,这也就是为啥 StringBuilder、StringBuffer可实现字符串修改功能了。下面来看部分常用方法的具体实现。

    append 方法

    append 的重构方法比较多,但原理是类似的。功能都是将字符串、字符数组等添加到原字符串中,并返回新的字符串 AbstractStringBuilder。步骤如下:(1)对传入形参正确性进行检查;(2)对原字符数组长度进行检查,判断是否能容纳新加入的字符;(3)对原字符数组进行相应添加操作。

    以形参为 String 在 append 方法源码为例。

    1     public AbstractStringBuilder append(String str) {
    2         if (str == null) str = "null";
    3         int len = str.length();
    4         ensureCapacityInternal(count + len);
    5         str.getChars(0, len, value, count);
    6         count += len;
    7         return this;
    8     }

    其中 ensureCapacityInternal 方法用于判断字符数组长度是否足够,如下所示:

    1     private void ensureCapacityInternal(int minimumCapacity) {
    2         // overflow-conscious code
    3         if (minimumCapacity - value.length > 0)
    4             expandCapacity(minimumCapacity);
    5     }

    当字符数组长度不够时,便创建一个新的数组,将原数组中数据拷贝到新数组中,具体拷贝方法由 Arrays.copyOf 方法实现,而 Arrays.copyOf 方法又是通过 System.arraycopy 来实现数组拷贝,该 System 方法为 native 方法。

    新的数组长度取决于原数组长度和待添加的数组长度,如下所示:

     1     void expandCapacity(int minimumCapacity) {
     2         int newCapacity = value.length * 2 + 2;
     3         if (newCapacity - minimumCapacity < 0)
     4             newCapacity = minimumCapacity;
     5         if (newCapacity < 0) {
     6             if (minimumCapacity < 0) // overflow
     7                 throw new OutOfMemoryError();
     8             newCapacity = Integer.MAX_VALUE;
     9         }
    10         value = Arrays.copyOf(value, newCapacity);
    11     }

    研究这段源码可以发现:如果可以提前预估出最终的数组长度并在创建对象时提前设置数组大小,对程序运行效率的提高是十分有帮助的。(减少了不断扩容、拷贝的内在及时间成本)

    append 相当重载方法源码如下:

      1     /**
      2      * Appends the string representation of the {@code Object} argument.
      3      * <p>
      4      * The overall effect is exactly as if the argument were converted
      5      * to a string by the method {@link String#valueOf(Object)},
      6      * and the characters of that string were then
      7      * {@link #append(String) appended} to this character sequence.
      8      *
      9      * @param   obj   an {@code Object}.
     10      * @return  a reference to this object.
     11      */
     12     public AbstractStringBuilder append(Object obj) {
     13         return append(String.valueOf(obj));
     14     }
     15 
     16     /**
     17      * Appends the specified string to this character sequence.
     18      * <p>
     19      * The characters of the {@code String} argument are appended, in
     20      * order, increasing the length of this sequence by the length of the
     21      * argument. If {@code str} is {@code null}, then the four
     22      * characters {@code "null"} are appended.
     23      * <p>
     24      * Let <i>n</i> be the length of this character sequence just prior to
     25      * execution of the {@code append} method. Then the character at
     26      * index <i>k</i> in the new character sequence is equal to the character
     27      * at index <i>k</i> in the old character sequence, if <i>k</i> is less
     28      * than <i>n</i>; otherwise, it is equal to the character at index
     29      * <i>k-n</i> in the argument {@code str}.
     30      *
     31      * @param   str   a string.
     32      * @return  a reference to this object.
     33      */
     34     public AbstractStringBuilder append(String str) {
     35         if (str == null) str = "null";
     36         int len = str.length();
     37         ensureCapacityInternal(count + len);
     38         str.getChars(0, len, value, count);
     39         count += len;
     40         return this;
     41     }
     42 
     43     // Documentation in subclasses because of synchro difference
     44     public AbstractStringBuilder append(StringBuffer sb) {
     45         if (sb == null)
     46             return append("null");
     47         int len = sb.length();
     48         ensureCapacityInternal(count + len);
     49         sb.getChars(0, len, value, count);
     50         count += len;
     51         return this;
     52     }
     53 
     54     // Documentation in subclasses because of synchro difference
     55     public AbstractStringBuilder append(CharSequence s) {
     56         if (s == null)
     57             s = "null";
     58         if (s instanceof String)
     59             return this.append((String)s);
     60         if (s instanceof StringBuffer)
     61             return this.append((StringBuffer)s);
     62         return this.append(s, 0, s.length());
     63     }
     64 
     65     /**
     66      * Appends a subsequence of the specified {@code CharSequence} to this
     67      * sequence.
     68      * <p>
     69      * Characters of the argument {@code s}, starting at
     70      * index {@code start}, are appended, in order, to the contents of
     71      * this sequence up to the (exclusive) index {@code end}. The length
     72      * of this sequence is increased by the value of {@code end - start}.
     73      * <p>
     74      * Let <i>n</i> be the length of this character sequence just prior to
     75      * execution of the {@code append} method. Then the character at
     76      * index <i>k</i> in this character sequence becomes equal to the
     77      * character at index <i>k</i> in this sequence, if <i>k</i> is less than
     78      * <i>n</i>; otherwise, it is equal to the character at index
     79      * <i>k+start-n</i> in the argument {@code s}.
     80      * <p>
     81      * If {@code s} is {@code null}, then this method appends
     82      * characters as if the s parameter was a sequence containing the four
     83      * characters {@code "null"}.
     84      *
     85      * @param   s the sequence to append.
     86      * @param   start   the starting index of the subsequence to be appended.
     87      * @param   end     the end index of the subsequence to be appended.
     88      * @return  a reference to this object.
     89      * @throws     IndexOutOfBoundsException if
     90      *             {@code start} is negative, or
     91      *             {@code start} is greater than {@code end} or
     92      *             {@code end} is greater than {@code s.length()}
     93      */
     94     public AbstractStringBuilder append(CharSequence s, int start, int end) {
     95         if (s == null)
     96             s = "null";
     97         if ((start < 0) || (start > end) || (end > s.length()))
     98             throw new IndexOutOfBoundsException(
     99                 "start " + start + ", end " + end + ", s.length() "
    100                 + s.length());
    101         int len = end - start;
    102         ensureCapacityInternal(count + len);
    103         for (int i = start, j = count; i < end; i++, j++)
    104             value[j] = s.charAt(i);
    105         count += len;
    106         return this;
    107     }
    108 
    109     /**
    110      * Appends the string representation of the {@code char} array
    111      * argument to this sequence.
    112      * <p>
    113      * The characters of the array argument are appended, in order, to
    114      * the contents of this sequence. The length of this sequence
    115      * increases by the length of the argument.
    116      * <p>
    117      * The overall effect is exactly as if the argument were converted
    118      * to a string by the method {@link String#valueOf(char[])},
    119      * and the characters of that string were then
    120      * {@link #append(String) appended} to this character sequence.
    121      *
    122      * @param   str   the characters to be appended.
    123      * @return  a reference to this object.
    124      */
    125     public AbstractStringBuilder append(char[] str) {
    126         int len = str.length;
    127         ensureCapacityInternal(count + len);
    128         System.arraycopy(str, 0, value, count, len);
    129         count += len;
    130         return this;
    131     }
    132 
    133     /**
    134      * Appends the string representation of a subarray of the
    135      * {@code char} array argument to this sequence.
    136      * <p>
    137      * Characters of the {@code char} array {@code str}, starting at
    138      * index {@code offset}, are appended, in order, to the contents
    139      * of this sequence. The length of this sequence increases
    140      * by the value of {@code len}.
    141      * <p>
    142      * The overall effect is exactly as if the arguments were converted
    143      * to a string by the method {@link String#valueOf(char[],int,int)},
    144      * and the characters of that string were then
    145      * {@link #append(String) appended} to this character sequence.
    146      *
    147      * @param   str      the characters to be appended.
    148      * @param   offset   the index of the first {@code char} to append.
    149      * @param   len      the number of {@code char}s to append.
    150      * @return  a reference to this object.
    151      * @throws IndexOutOfBoundsException
    152      *         if {@code offset < 0} or {@code len < 0}
    153      *         or {@code offset+len > str.length}
    154      */
    155     public AbstractStringBuilder append(char str[], int offset, int len) {
    156         if (len > 0)                // let arraycopy report AIOOBE for len < 0
    157             ensureCapacityInternal(count + len);
    158         System.arraycopy(str, offset, value, count, len);
    159         count += len;
    160         return this;
    161     }
    162 
    163     /**
    164      * Appends the string representation of the {@code boolean}
    165      * argument to the sequence.
    166      * <p>
    167      * The overall effect is exactly as if the argument were converted
    168      * to a string by the method {@link String#valueOf(boolean)},
    169      * and the characters of that string were then
    170      * {@link #append(String) appended} to this character sequence.
    171      *
    172      * @param   b   a {@code boolean}.
    173      * @return  a reference to this object.
    174      */
    175     public AbstractStringBuilder append(boolean b) {
    176         if (b) {
    177             ensureCapacityInternal(count + 4);
    178             value[count++] = 't';
    179             value[count++] = 'r';
    180             value[count++] = 'u';
    181             value[count++] = 'e';
    182         } else {
    183             ensureCapacityInternal(count + 5);
    184             value[count++] = 'f';
    185             value[count++] = 'a';
    186             value[count++] = 'l';
    187             value[count++] = 's';
    188             value[count++] = 'e';
    189         }
    190         return this;
    191     }
    192 
    193     /**
    194      * Appends the string representation of the {@code char}
    195      * argument to this sequence.
    196      * <p>
    197      * The argument is appended to the contents of this sequence.
    198      * The length of this sequence increases by {@code 1}.
    199      * <p>
    200      * The overall effect is exactly as if the argument were converted
    201      * to a string by the method {@link String#valueOf(char)},
    202      * and the character in that string were then
    203      * {@link #append(String) appended} to this character sequence.
    204      *
    205      * @param   c   a {@code char}.
    206      * @return  a reference to this object.
    207      */
    208     public AbstractStringBuilder append(char c) {
    209         ensureCapacityInternal(count + 1);
    210         value[count++] = c;
    211         return this;
    212     }
    213 
    214     /**
    215      * Appends the string representation of the {@code int}
    216      * argument to this sequence.
    217      * <p>
    218      * The overall effect is exactly as if the argument were converted
    219      * to a string by the method {@link String#valueOf(int)},
    220      * and the characters of that string were then
    221      * {@link #append(String) appended} to this character sequence.
    222      *
    223      * @param   i   an {@code int}.
    224      * @return  a reference to this object.
    225      */
    226     public AbstractStringBuilder append(int i) {
    227         if (i == Integer.MIN_VALUE) {
    228             append("-2147483648");
    229             return this;
    230         }
    231         int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
    232                                      : Integer.stringSize(i);
    233         int spaceNeeded = count + appendedLength;
    234         ensureCapacityInternal(spaceNeeded);
    235         Integer.getChars(i, spaceNeeded, value);
    236         count = spaceNeeded;
    237         return this;
    238     }
    239 
    240     /**
    241      * Appends the string representation of the {@code long}
    242      * argument to this sequence.
    243      * <p>
    244      * The overall effect is exactly as if the argument were converted
    245      * to a string by the method {@link String#valueOf(long)},
    246      * and the characters of that string were then
    247      * {@link #append(String) appended} to this character sequence.
    248      *
    249      * @param   l   a {@code long}.
    250      * @return  a reference to this object.
    251      */
    252     public AbstractStringBuilder append(long l) {
    253         if (l == Long.MIN_VALUE) {
    254             append("-9223372036854775808");
    255             return this;
    256         }
    257         int appendedLength = (l < 0) ? Long.stringSize(-l) + 1
    258                                      : Long.stringSize(l);
    259         int spaceNeeded = count + appendedLength;
    260         ensureCapacityInternal(spaceNeeded);
    261         Long.getChars(l, spaceNeeded, value);
    262         count = spaceNeeded;
    263         return this;
    264     }
    265 
    266     /**
    267      * Appends the string representation of the {@code float}
    268      * argument to this sequence.
    269      * <p>
    270      * The overall effect is exactly as if the argument were converted
    271      * to a string by the method {@link String#valueOf(float)},
    272      * and the characters of that string were then
    273      * {@link #append(String) appended} to this character sequence.
    274      *
    275      * @param   f   a {@code float}.
    276      * @return  a reference to this object.
    277      */
    278     public AbstractStringBuilder append(float f) {
    279         new FloatingDecimal(f).appendTo(this);
    280         return this;
    281     }
    282 
    283     /**
    284      * Appends the string representation of the {@code double}
    285      * argument to this sequence.
    286      * <p>
    287      * The overall effect is exactly as if the argument were converted
    288      * to a string by the method {@link String#valueOf(double)},
    289      * and the characters of that string were then
    290      * {@link #append(String) appended} to this character sequence.
    291      *
    292      * @param   d   a {@code double}.
    293      * @return  a reference to this object.
    294      */
    295     public AbstractStringBuilder append(double d) {
    296         new FloatingDecimal(d).appendTo(this);
    297         return this;
    298     }
    View Code

    delete,replace,insert 方法

    这三个方法的实现原理相似。

    delete:可实现删除指定数组起始、终止位置之间的字符。将指定终止位置之后的字符依次向前移动 len 个字符,将起始位置的字符开始依次覆盖掉,相当于字符数组拷贝。

    replace:字符数组拷贝。

    insert:在数组指定位置插入字符,底层也是字符数组拷贝。

    其源码如下:

      1     /**
      2      * Removes the characters in a substring of this sequence.
      3      * The substring begins at the specified {@code start} and extends to
      4      * the character at index {@code end - 1} or to the end of the
      5      * sequence if no such character exists. If
      6      * {@code start} is equal to {@code end}, no changes are made.
      7      *
      8      * @param      start  The beginning index, inclusive.
      9      * @param      end    The ending index, exclusive.
     10      * @return     This object.
     11      * @throws     StringIndexOutOfBoundsException  if {@code start}
     12      *             is negative, greater than {@code length()}, or
     13      *             greater than {@code end}.
     14      */
     15     public AbstractStringBuilder delete(int start, int end) {
     16         if (start < 0)
     17             throw new StringIndexOutOfBoundsException(start);
     18         if (end > count)
     19             end = count;
     20         if (start > end)
     21             throw new StringIndexOutOfBoundsException();
     22         int len = end - start;
     23         if (len > 0) {
     24             System.arraycopy(value, start+len, value, start, count-end);
     25             count -= len;
     26         }
     27         return this;
     28     }
     29 
     30     /**
     31      * Replaces the characters in a substring of this sequence
     32      * with characters in the specified <code>String</code>. The substring
     33      * begins at the specified <code>start</code> and extends to the character
     34      * at index <code>end - 1</code> or to the end of the
     35      * sequence if no such character exists. First the
     36      * characters in the substring are removed and then the specified
     37      * <code>String</code> is inserted at <code>start</code>. (This
     38      * sequence will be lengthened to accommodate the
     39      * specified String if necessary.)
     40      *
     41      * @param      start    The beginning index, inclusive.
     42      * @param      end      The ending index, exclusive.
     43      * @param      str   String that will replace previous contents.
     44      * @return     This object.
     45      * @throws     StringIndexOutOfBoundsException  if <code>start</code>
     46      *             is negative, greater than <code>length()</code>, or
     47      *             greater than <code>end</code>.
     48      */
     49     public AbstractStringBuilder replace(int start, int end, String str) {
     50         if (start < 0)
     51             throw new StringIndexOutOfBoundsException(start);
     52         if (start > count)
     53             throw new StringIndexOutOfBoundsException("start > length()");
     54         if (start > end)
     55             throw new StringIndexOutOfBoundsException("start > end");
     56 
     57         if (end > count)
     58             end = count;
     59         int len = str.length();
     60         int newCount = count + len - (end - start);
     61         ensureCapacityInternal(newCount);
     62 
     63         System.arraycopy(value, end, value, start + len, count - end);
     64         str.getChars(value, start);
     65         count = newCount;
     66         return this;
     67     }
     68 
     69     /**
     70      * Inserts the string representation of a subarray of the {@code str}
     71      * array argument into this sequence. The subarray begins at the
     72      * specified {@code offset} and extends {@code len} {@code char}s.
     73      * The characters of the subarray are inserted into this sequence at
     74      * the position indicated by {@code index}. The length of this
     75      * sequence increases by {@code len} {@code char}s.
     76      *
     77      * @param      index    position at which to insert subarray.
     78      * @param      str       A {@code char} array.
     79      * @param      offset   the index of the first {@code char} in subarray to
     80      *             be inserted.
     81      * @param      len      the number of {@code char}s in the subarray to
     82      *             be inserted.
     83      * @return     This object
     84      * @throws     StringIndexOutOfBoundsException  if {@code index}
     85      *             is negative or greater than {@code length()}, or
     86      *             {@code offset} or {@code len} are negative, or
     87      *             {@code (offset+len)} is greater than
     88      *             {@code str.length}.
     89      */
     90     public AbstractStringBuilder insert(int index, char[] str, int offset,
     91                                         int len)
     92     {
     93         if ((index < 0) || (index > length()))
     94             throw new StringIndexOutOfBoundsException(index);
     95         if ((offset < 0) || (len < 0) || (offset > str.length - len))
     96             throw new StringIndexOutOfBoundsException(
     97                 "offset " + offset + ", len " + len + ", str.length "
     98                 + str.length);
     99         ensureCapacityInternal(count + len);
    100         System.arraycopy(value, index, value, index + len, count - index);
    101         System.arraycopy(str, offset, value, index, len);
    102         count += len;
    103         return this;
    104     }
    View Code

    toString 方法

    该方法是此抽象类中唯一一个抽象方法,功能就不多说了。

    总结

    java.lang.StringBuilder 和 java.lang.StringBuffer 只是对 java.lang.AbstractStringBuilder 的一个继承封装,通过继承可以实现功能的一个拓展。StringBuilder仅仅只是功能的继承;StirngBuffer在功能继承上做了一个synchronized加锁的操作,从而实现线程安全性。

    AbstractStringBuilder 才是功能方法的具体实现。同 java.lang.String 一样,底层是用字符数组在存储字符串,但区别是 String 中字符数组是 final 类型,而 AbstractStringBuilder 中字符数组是可变的。

    StringBuilder 与 StringBuffer 均是 final 类,无法再被继承。

  • 相关阅读:
    理解FreeRTOS的任务状态机制
    stm32【按键处理:单击、连击、长按】
    stm32f4单片机 硬件浮点运算
    stm32 HAL库 串口无法接收数据的问题
    Single Sign On —— 简介(转)
    关于第三方库安装时很慢或者读取超时问题处理
    设计模式》状态机模式
    设计模式》责任链模式
    设计模式》访问者模式
    设计模式》策略者模式
  • 原文地址:https://www.cnblogs.com/hthuang/p/5495554.html
Copyright © 2020-2023  润新知