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     }

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     }

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 }

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     }

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     }

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     }

toString 方法

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

总结

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

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

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java达人

Java 8 Stream 教程 (二)

作者:Benjamin 译者:java达人 来源:http://winterbe.com/posts/2014/07/31/java8-stream-tuto...

19510
来自专栏pangguoming

C#异步编程

1143
来自专栏Jerry的SAP技术分享

Java和ABAP中的几种引用类型的分析和比较

Java编程语言中几种不同的引用类型是面试时经常容易被问到的问题:强引用,软引用,弱引用,虚引用。

703
来自专栏技术专栏

慕课网高并发实战(六)- 线程安全策略

ThreadLocal 实例保存登录用户信息 (具体的业务场景,和拦截器的使用就不赘述了,大家可以购买课程详细学习)

702
来自专栏yl 成长笔记

c# 读取 txt 文件中数据(int)

今天在学图的算法做测试是,需要读取文本文件中的点坐标,本来很简单的事情,折腾了半天,记录一下找到的一种简单粗暴的解决方法,以便以后查看。

1275
来自专栏逸鹏说道

Python3 与 C# 扩展之~基础衍生

在线编程: https://mybinder.org/v2/gh/lotapp/BaseCode/master

823
来自专栏Android Note

Kotlin —  最佳实践

1122
来自专栏服务端技术杂谈

Java编码规范

命名 类名使用UpperCamelCase风格。 领域模型相关命名:DO / DTO / VO / DAO等。 方法名,参数名,成员变量,局部变量都统一使用lo...

2674
来自专栏微信公众号:Java团长

Java习惯用法总结

在Java编程中,有些知识 并不能仅通过语言规范或者标准API文档就能学到的。在本文中,我会尽量收集一些最常用的习惯用法,特别是很难猜到的用法。

701
来自专栏Java爬坑系列

【Java入门提高篇】Day9 Java内部类——静态内部类

  今天来说说Java中的最后一种内部类——静态内部类   所谓的静态内部类,自然就是用static修饰的内部类,那用static修饰过后的内部类,跟一般的内部...

1946

扫码关注云+社区