一直以来,都是看到网上说“ 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 类,无法再被继承。