一直以来,都是看到网上说“ 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. * Appends the specified <code>CharSequence</code> to this
  42. * sequence.
  43. * <p>
  44. * The characters of the <code>CharSequence</code> argument are appended,
  45. * in order, increasing the length of this sequence by the length of the
  46. * argument.
  47. *
  48. * <p>The result of this method is exactly the same as if it were an
  49. * invocation of this.append(s, 0, s.length());
  50. *
  51. * <p>This method synchronizes on this (the destination)
  52. * object but does not synchronize on the source (<code>s</code>).
  53. *
  54. * <p>If <code>s</code> is <code>null</code>, then the four characters
  55. * <code>"null"</code> are appended.
  56. *
  57. * @param s the <code>CharSequence</code> to append.
  58. * @return a reference to this object.
  59. * @since 1.5
  60. */
  61. public StringBuffer append(CharSequence s) {
  62. // Note, synchronization achieved via other invocations
  63. if (s == null)
  64. s = "null";
  65. if (s instanceof String)
  66. return this.append((String)s);
  67. if (s instanceof StringBuffer)
  68. return this.append((StringBuffer)s);
  69. return this.append(s, 0, s.length());
  70. }
  71.  
  72. /**
  73. * @throws IndexOutOfBoundsException {@inheritDoc}
  74. * @since 1.5
  75. */
  76. public synchronized StringBuffer append(CharSequence s, int start, int end)
  77. {
  78. super.append(s, start, end);
  79. return this;
  80. }
  81.  
  82. public synchronized StringBuffer append(char[] str) {
  83. super.append(str);
  84. return this;
  85. }
  86.  
  87. /**
  88. * @throws IndexOutOfBoundsException {@inheritDoc}
  89. */
  90. public synchronized StringBuffer append(char[] str, int offset, int len) {
  91. super.append(str, offset, len);
  92. return this;
  93. }
  94.  
  95. public synchronized StringBuffer append(boolean b) {
  96. super.append(b);
  97. return this;
  98. }
  99.  
  100. public synchronized StringBuffer append(char c) {
  101. super.append(c);
  102. return this;
  103. }
  104.  
  105. public synchronized StringBuffer append(int i) {
  106. super.append(i);
  107. return this;
  108. }
  109.  
  110. /**
  111. * @since 1.5
  112. */
  113. public synchronized StringBuffer appendCodePoint(int codePoint) {
  114. super.appendCodePoint(codePoint);
  115. return this;
  116. }
  117.  
  118. public synchronized StringBuffer append(long lng) {
  119. super.append(lng);
  120. return this;
  121. }
  122.  
  123. public synchronized StringBuffer append(float f) {
  124. super.append(f);
  125. return this;
  126. }
  127.  
  128. public synchronized StringBuffer append(double d) {
  129. super.append(d);
  130. return this;
  131. }

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 类,无法再被继承。

Java源码学习 -- java.lang.StringBuilder,java.lang.StringBuffer,java.lang.AbstractStringBuilder的更多相关文章

  1. 在IDEA中搭建Java源码学习环境并上传到GitHub上

    打开IDEA新建一个项目 创建一个最简单的Java项目即可 在项目命名填写该项目的名称,我这里写的项目名为Java_Source_Study 点击Finished,然后在项目的src目录下新建源码文件 ...

  2. JDK源码学习系列03----StringBuffer+StringBuilder

                         JDK源码学习系列03----StringBuffer+StringBuilder 由于前面学习了StringBuffer和StringBuilder的父类A ...

  3. Java源码学习 -- java.lang.String

    java.lang.String是使用频率非常高的类.要想更好的使用java.lang.String类,了解其源代码实现是非常有必要的.由java.lang.String,自然联想到java.lang ...

  4. Java 源码学习系列(三)——Integer

    Integer 类在对象中包装了一个基本类型 int 的值.Integer 类型的对象包含一个 int 类型的字段. 此外,该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还 ...

  5. Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库

    http://www.iteye.com/topic/1113732 原则网址 Java源码初接触 如果你进行过一年左右的开发,喜欢用eclipse的debug功能.好了,你现在就有阅读源码的技术基础 ...

  6. java源码学习(一)String

    String表示字符串,Java中所有字符串的字面值都是String类的实例,例如"ABC".字符串是常量,在定义之后不能被改变,字符串缓冲区支持可变的字符串.因为 String ...

  7. java源码学习(二)Integer

    Integer类包含了一个原始基本类型int.Integer属性中就一个属性,它的类型就是int. 此外,这个类还提供了几个把int转成String和把String转成int的方法,同样也提供了其它跟 ...

  8. java源码学习(四)ArrayList

    ArrayList ​ ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ​ ArrayList不是线程安全的,只能用在单线程环境下, ...

  9. Java源码学习:HashMap实现原理

    AbstractMap HashMap继承制AbstractMap,很多通用的方法,比如size().isEmpty(),都已经在这里实现了.来看一个比较简单的方法,get方法: public V g ...

随机推荐

  1. Async/Await替代Promise的6个理由

    译者按: Node.js的异步编程方式有效提高了应用性能:然而回调地狱却让人望而生畏,Promise让我们告别回调函数,写出更优雅的异步代码:在实践过程中,却发现Promise并不完美:技术进步是无止 ...

  2. 老李分享:天使投资 vs. 风险投资 vs. 私募股权融资

    天使投资(Angel Capital) 创意阶段(idea stage)到种子阶段(seed stage) 0 – 1百万美元营业额 还没有盈利 小股东 风险异常的高 不存在负债情况 风险投资(Ven ...

  3. Android之利用正则表达式校验邮箱、手机号、密码、身份证号码等

    概述 现在Android应用在注册的时候基本会校验邮箱.手机号.密码.身份证号码其中一项或多项,特此收集了相关的正则表达式给大家分享.除了正则表达式,文章末尾提供Demo中有惊喜哦! 具体验证的图片效 ...

  4. OS X background process

    Types of Background Process 1. login item 2. xpc service 3. daemon/agent (也可以叫 mach service) 4. star ...

  5. Excel import

    Case Study: Reading cell content from excel template for COM variant type VT_R4 or VT_R8 is always l ...

  6. ios deprecated 警告消除 强迫症的选择

    #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" ...

  7. 在github上搭建免费的博客

    github好多年前,大家都开始玩啦,我这个菜鸟近几年才开始.github不仅可以管理项目,还可以搭建博客.技术人员,一般用的博客为博客园,CSDN多一些.看到朋友们都弄一个,我也开始弄起来,先找点资 ...

  8. 纯原生javascript实现分页效果

    随着近几年前端行业的迅猛发展,各种层出不穷的新框架,新方法让我们有点眼花缭乱. 最近刚好比较清闲,所以没事准备撸撸前端的根基javascript,纯属练练手,写个分页,顺便跟大家分享一下 functi ...

  9. 从源码角度入手实现RecyclerView的Item点击事件

    RecyclerView 作为 ListView 和 GridView 的替代产物,相信在Android界已广为流传. RecyclerView 本是不会有类似 ListView 的那种点击事件,但是 ...

  10. 读书笔记 effective c++ Item 53 关注编译器发出的警告

    许多程序员常常忽略编译器发出的警告.毕竟,如果问题很严重,它才将会变成一个error,不是么?相对来说,这个想法可能在其它语言是无害的,但是在C++中,我敢打赌编译器的实现者对于对接下来会发生什么比你 ...