一直以来,都是看到网上说“ 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 类,不能被继承。其类继承父类和实现的接口关系如下所示:

 public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{}

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

     /**
* Constructs a string builder with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuilder() {
super(16);
} /**
* Constructs a string builder with no characters in it and an
* initial capacity specified by the <code>capacity</code> argument.
*
* @param capacity the initial capacity.
* @throws NegativeArraySizeException if the <code>capacity</code>
* argument is less than <code>0</code>.
*/
public StringBuilder(int capacity) {
super(capacity);
} /**
* Constructs a string builder initialized to the contents of the
* specified string. The initial capacity of the string builder is
* <code>16</code> plus the length of the string argument.
*
* @param str the initial contents of the buffer.
* @throws NullPointerException if <code>str</code> is <code>null</code>
*/
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
} /**
* Constructs a string builder that contains the same characters
* as the specified <code>CharSequence</code>. The initial capacity of
* the string builder is <code>16</code> plus the length of the
* <code>CharSequence</code> argument.
*
* @param seq the sequence to copy.
* @throws NullPointerException if <code>seq</code> is <code>null</code>
*/
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}

append 方法

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

     public StringBuilder append(String str) {
super.append(str);
return this;
}

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

     public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
} public StringBuilder append(String str) {
super.append(str);
return this;
} // Appends the specified string builder to this sequence.
private StringBuilder append(StringBuilder sb) {
if (sb == null)
return append("null");
int len = sb.length();
int newcount = count + len;
if (newcount > value.length)
expandCapacity(newcount);
sb.getChars(0, len, value, count);
count = newcount;
return this;
} /**
* Appends the specified <tt>StringBuffer</tt> to this sequence.
* <p>
* The characters of the <tt>StringBuffer</tt> argument are appended,
* in order, to this sequence, increasing the
* length of this sequence by the length of the argument.
* If <tt>sb</tt> is <tt>null</tt>, then the four characters
* <tt>"null"</tt> are appended to this sequence.
* <p>
* Let <i>n</i> be the length of this character sequence just prior to
* execution of the <tt>append</tt> method. Then the character at index
* <i>k</i> in the new character sequence is equal to the character at
* index <i>k</i> in the old character sequence, if <i>k</i> is less than
* <i>n</i>; otherwise, it is equal to the character at index <i>k-n</i>
* in the argument <code>sb</code>.
*
* @param sb the <tt>StringBuffer</tt> to append.
* @return a reference to this object.
*/
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
} /**
*/
public StringBuilder append(CharSequence s) {
if (s == null)
s = "null";
if (s instanceof String)
return this.append((String)s);
if (s instanceof StringBuffer)
return this.append((StringBuffer)s);
if (s instanceof StringBuilder)
return this.append((StringBuilder)s);
return this.append(s, 0, s.length());
} /**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public StringBuilder append(CharSequence s, int start, int end) {
super.append(s, start, end);
return this;
} public StringBuilder append(char[] str) {
super.append(str);
return this;
} /**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public StringBuilder append(char[] str, int offset, int len) {
super.append(str, offset, len);
return this;
} public StringBuilder append(boolean b) {
super.append(b);
return this;
} public StringBuilder append(char c) {
super.append(c);
return this;
} public StringBuilder append(int i) {
super.append(i);
return this;
} public StringBuilder append(long lng) {
super.append(lng);
return this;
} public StringBuilder append(float f) {
super.append(f);
return this;
} public StringBuilder append(double d) {
super.append(d);
return this;
}

toString 方法

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

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

java.lang.StringBuffer

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

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

  public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{ /** use serialVersionUID from JDK 1.0.2 for interoperability */
static final long serialVersionUID = 3388685877147921107L; /**
* Constructs a string buffer with no characters in it and an
* initial capacity of 16 characters.
*/
public StringBuffer() {
super(16);
} /**
* Constructs a string buffer with no characters in it and
* the specified initial capacity.
*
* @param capacity the initial capacity.
* @exception NegativeArraySizeException if the <code>capacity</code>
* argument is less than <code>0</code>.
*/
public StringBuffer(int capacity) {
super(capacity);
} /**
* Constructs a string buffer initialized to the contents of the
* specified string. The initial capacity of the string buffer is
* <code>16</code> plus the length of the string argument.
*
* @param str the initial contents of the buffer.
* @exception NullPointerException if <code>str</code> is <code>null</code>
*/
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
} /**
* Constructs a string buffer that contains the same characters
* as the specified <code>CharSequence</code>. The initial capacity of
* the string buffer is <code>16</code> plus the length of the
* <code>CharSequence</code> argument.
* <p>
* If the length of the specified <code>CharSequence</code> is
* less than or equal to zero, then an empty buffer of capacity
* <code>16</code> is returned.
*
* @param seq the sequence to copy.
* @exception NullPointerException if <code>seq</code> is <code>null</code>
* @since 1.5
*/
public StringBuffer(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
}

append 功能方法源码如下:

     public synchronized StringBuffer append(Object obj) {
super.append(String.valueOf(obj));
return this;
} public synchronized StringBuffer append(String str) {
super.append(str);
return this;
} /**
* Appends the specified <tt>StringBuffer</tt> to this sequence.
* <p>
* The characters of the <tt>StringBuffer</tt> argument are appended,
* in order, to the contents of this <tt>StringBuffer</tt>, increasing the
* length of this <tt>StringBuffer</tt> by the length of the argument.
* If <tt>sb</tt> is <tt>null</tt>, then the four characters
* <tt>"null"</tt> are appended to this <tt>StringBuffer</tt>.
* <p>
* Let <i>n</i> be the length of the old character sequence, the one
* contained in the <tt>StringBuffer</tt> just prior to execution of the
* <tt>append</tt> method. Then the character at index <i>k</i> in
* the new character sequence is equal to the character at index <i>k</i>
* in the old character sequence, if <i>k</i> is less than <i>n</i>;
* otherwise, it is equal to the character at index <i>k-n</i> in the
* argument <code>sb</code>.
* <p>
* This method synchronizes on <code>this</code> (the destination)
* object but does not synchronize on the source (<code>sb</code>).
*
* @param sb the <tt>StringBuffer</tt> to append.
* @return a reference to this object.
* @since 1.4
*/
public synchronized StringBuffer append(StringBuffer sb) {
super.append(sb);
return this;
} /**
* Appends the specified <code>CharSequence</code> to this
* sequence.
* <p>
* The characters of the <code>CharSequence</code> argument are appended,
* in order, increasing the length of this sequence by the length of the
* argument.
*
* <p>The result of this method is exactly the same as if it were an
* invocation of this.append(s, 0, s.length());
*
* <p>This method synchronizes on this (the destination)
* object but does not synchronize on the source (<code>s</code>).
*
* <p>If <code>s</code> is <code>null</code>, then the four characters
* <code>"null"</code> are appended.
*
* @param s the <code>CharSequence</code> to append.
* @return a reference to this object.
* @since 1.5
*/
public StringBuffer append(CharSequence s) {
// Note, synchronization achieved via other invocations
if (s == null)
s = "null";
if (s instanceof String)
return this.append((String)s);
if (s instanceof StringBuffer)
return this.append((StringBuffer)s);
return this.append(s, 0, s.length());
} /**
* @throws IndexOutOfBoundsException {@inheritDoc}
* @since 1.5
*/
public synchronized StringBuffer append(CharSequence s, int start, int end)
{
super.append(s, start, end);
return this;
} public synchronized StringBuffer append(char[] str) {
super.append(str);
return this;
} /**
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public synchronized StringBuffer append(char[] str, int offset, int len) {
super.append(str, offset, len);
return this;
} public synchronized StringBuffer append(boolean b) {
super.append(b);
return this;
} public synchronized StringBuffer append(char c) {
super.append(c);
return this;
} public synchronized StringBuffer append(int i) {
super.append(i);
return this;
} /**
* @since 1.5
*/
public synchronized StringBuffer appendCodePoint(int codePoint) {
super.appendCodePoint(codePoint);
return this;
} public synchronized StringBuffer append(long lng) {
super.append(lng);
return this;
} public synchronized StringBuffer append(float f) {
super.append(f);
return this;
} public synchronized StringBuffer append(double d) {
super.append(d);
return this;
}

java.lang.AbstractStringBuilder

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

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

 abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value; /**
* The count is the number of characters used.
*/
int count; /**
* This no-arg constructor is necessary for serialization of subclasses.
*/
AbstractStringBuilder() {
} /**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
}

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

append 方法

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

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

     public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}

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

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

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

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

     void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}

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

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

     /**
* Appends the string representation of the {@code Object} argument.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(Object)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param obj an {@code Object}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
} /**
* Appends the specified string to this character sequence.
* <p>
* The characters of the {@code String} argument are appended, in
* order, increasing the length of this sequence by the length of the
* argument. If {@code str} is {@code null}, then the four
* characters {@code "null"} are appended.
* <p>
* Let <i>n</i> be the length of this character sequence just prior to
* execution of the {@code append} method. Then the character at
* index <i>k</i> in the new character sequence is equal to the character
* at index <i>k</i> in the old character sequence, if <i>k</i> is less
* than <i>n</i>; otherwise, it is equal to the character at index
* <i>k-n</i> in the argument {@code str}.
*
* @param str a string.
* @return a reference to this object.
*/
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
} // Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(StringBuffer sb) {
if (sb == null)
return append("null");
int len = sb.length();
ensureCapacityInternal(count + len);
sb.getChars(0, len, value, count);
count += len;
return this;
} // Documentation in subclasses because of synchro difference
public AbstractStringBuilder append(CharSequence s) {
if (s == null)
s = "null";
if (s instanceof String)
return this.append((String)s);
if (s instanceof StringBuffer)
return this.append((StringBuffer)s);
return this.append(s, 0, s.length());
} /**
* Appends a subsequence of the specified {@code CharSequence} to this
* sequence.
* <p>
* Characters of the argument {@code s}, starting at
* index {@code start}, are appended, in order, to the contents of
* this sequence up to the (exclusive) index {@code end}. The length
* of this sequence is increased by the value of {@code end - start}.
* <p>
* Let <i>n</i> be the length of this character sequence just prior to
* execution of the {@code append} method. Then the character at
* index <i>k</i> in this character sequence becomes equal to the
* character at index <i>k</i> in this sequence, if <i>k</i> is less than
* <i>n</i>; otherwise, it is equal to the character at index
* <i>k+start-n</i> in the argument {@code s}.
* <p>
* If {@code s} is {@code null}, then this method appends
* characters as if the s parameter was a sequence containing the four
* characters {@code "null"}.
*
* @param s the sequence to append.
* @param start the starting index of the subsequence to be appended.
* @param end the end index of the subsequence to be appended.
* @return a reference to this object.
* @throws IndexOutOfBoundsException if
* {@code start} is negative, or
* {@code start} is greater than {@code end} or
* {@code end} is greater than {@code s.length()}
*/
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null)
s = "null";
if ((start < 0) || (start > end) || (end > s.length()))
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", s.length() "
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
for (int i = start, j = count; i < end; i++, j++)
value[j] = s.charAt(i);
count += len;
return this;
} /**
* Appends the string representation of the {@code char} array
* argument to this sequence.
* <p>
* The characters of the array argument are appended, in order, to
* the contents of this sequence. The length of this sequence
* increases by the length of the argument.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(char[])},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param str the characters to be appended.
* @return a reference to this object.
*/
public AbstractStringBuilder append(char[] str) {
int len = str.length;
ensureCapacityInternal(count + len);
System.arraycopy(str, 0, value, count, len);
count += len;
return this;
} /**
* Appends the string representation of a subarray of the
* {@code char} array argument to this sequence.
* <p>
* Characters of the {@code char} array {@code str}, starting at
* index {@code offset}, are appended, in order, to the contents
* of this sequence. The length of this sequence increases
* by the value of {@code len}.
* <p>
* The overall effect is exactly as if the arguments were converted
* to a string by the method {@link String#valueOf(char[],int,int)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param str the characters to be appended.
* @param offset the index of the first {@code char} to append.
* @param len the number of {@code char}s to append.
* @return a reference to this object.
* @throws IndexOutOfBoundsException
* if {@code offset < 0} or {@code len < 0}
* or {@code offset+len > str.length}
*/
public AbstractStringBuilder append(char str[], int offset, int len) {
if (len > 0) // let arraycopy report AIOOBE for len < 0
ensureCapacityInternal(count + len);
System.arraycopy(str, offset, value, count, len);
count += len;
return this;
} /**
* Appends the string representation of the {@code boolean}
* argument to the sequence.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(boolean)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param b a {@code boolean}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(boolean b) {
if (b) {
ensureCapacityInternal(count + 4);
value[count++] = 't';
value[count++] = 'r';
value[count++] = 'u';
value[count++] = 'e';
} else {
ensureCapacityInternal(count + 5);
value[count++] = 'f';
value[count++] = 'a';
value[count++] = 'l';
value[count++] = 's';
value[count++] = 'e';
}
return this;
} /**
* Appends the string representation of the {@code char}
* argument to this sequence.
* <p>
* The argument is appended to the contents of this sequence.
* The length of this sequence increases by {@code 1}.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(char)},
* and the character in that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param c a {@code char}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
} /**
* Appends the string representation of the {@code int}
* argument to this sequence.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(int)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param i an {@code int}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(int i) {
if (i == Integer.MIN_VALUE) {
append("-2147483648");
return this;
}
int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
: Integer.stringSize(i);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Integer.getChars(i, spaceNeeded, value);
count = spaceNeeded;
return this;
} /**
* Appends the string representation of the {@code long}
* argument to this sequence.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(long)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param l a {@code long}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(long l) {
if (l == Long.MIN_VALUE) {
append("-9223372036854775808");
return this;
}
int appendedLength = (l < 0) ? Long.stringSize(-l) + 1
: Long.stringSize(l);
int spaceNeeded = count + appendedLength;
ensureCapacityInternal(spaceNeeded);
Long.getChars(l, spaceNeeded, value);
count = spaceNeeded;
return this;
} /**
* Appends the string representation of the {@code float}
* argument to this sequence.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(float)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param f a {@code float}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(float f) {
new FloatingDecimal(f).appendTo(this);
return this;
} /**
* Appends the string representation of the {@code double}
* argument to this sequence.
* <p>
* The overall effect is exactly as if the argument were converted
* to a string by the method {@link String#valueOf(double)},
* and the characters of that string were then
* {@link #append(String) appended} to this character sequence.
*
* @param d a {@code double}.
* @return a reference to this object.
*/
public AbstractStringBuilder append(double d) {
new FloatingDecimal(d).appendTo(this);
return this;
}

delete,replace,insert 方法

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

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

replace:字符数组拷贝。

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

其源码如下:

     /**
* Removes the characters in a substring of this sequence.
* The substring begins at the specified {@code start} and extends to
* the character at index {@code end - 1} or to the end of the
* sequence if no such character exists. If
* {@code start} is equal to {@code end}, no changes are made.
*
* @param start The beginning index, inclusive.
* @param end The ending index, exclusive.
* @return This object.
* @throws StringIndexOutOfBoundsException if {@code start}
* is negative, greater than {@code length()}, or
* greater than {@code end}.
*/
public AbstractStringBuilder delete(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
end = count;
if (start > end)
throw new StringIndexOutOfBoundsException();
int len = end - start;
if (len > 0) {
System.arraycopy(value, start+len, value, start, count-end);
count -= len;
}
return this;
} /**
* Replaces the characters in a substring of this sequence
* with characters in the specified <code>String</code>. The substring
* begins at the specified <code>start</code> and extends to the character
* at index <code>end - 1</code> or to the end of the
* sequence if no such character exists. First the
* characters in the substring are removed and then the specified
* <code>String</code> is inserted at <code>start</code>. (This
* sequence will be lengthened to accommodate the
* specified String if necessary.)
*
* @param start The beginning index, inclusive.
* @param end The ending index, exclusive.
* @param str String that will replace previous contents.
* @return This object.
* @throws StringIndexOutOfBoundsException if <code>start</code>
* is negative, greater than <code>length()</code>, or
* greater than <code>end</code>.
*/
public AbstractStringBuilder replace(int start, int end, String str) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (start > count)
throw new StringIndexOutOfBoundsException("start > length()");
if (start > end)
throw new StringIndexOutOfBoundsException("start > end"); if (end > count)
end = count;
int len = str.length();
int newCount = count + len - (end - start);
ensureCapacityInternal(newCount); System.arraycopy(value, end, value, start + len, count - end);
str.getChars(value, start);
count = newCount;
return this;
} /**
* Inserts the string representation of a subarray of the {@code str}
* array argument into this sequence. The subarray begins at the
* specified {@code offset} and extends {@code len} {@code char}s.
* The characters of the subarray are inserted into this sequence at
* the position indicated by {@code index}. The length of this
* sequence increases by {@code len} {@code char}s.
*
* @param index position at which to insert subarray.
* @param str A {@code char} array.
* @param offset the index of the first {@code char} in subarray to
* be inserted.
* @param len the number of {@code char}s in the subarray to
* be inserted.
* @return This object
* @throws StringIndexOutOfBoundsException if {@code index}
* is negative or greater than {@code length()}, or
* {@code offset} or {@code len} are negative, or
* {@code (offset+len)} is greater than
* {@code str.length}.
*/
public AbstractStringBuilder insert(int index, char[] str, int offset,
int len)
{
if ((index < 0) || (index > length()))
throw new StringIndexOutOfBoundsException(index);
if ((offset < 0) || (len < 0) || (offset > str.length - len))
throw new StringIndexOutOfBoundsException(
"offset " + offset + ", len " + len + ", str.length "
+ str.length);
ensureCapacityInternal(count + len);
System.arraycopy(value, index, value, index + len, count - index);
System.arraycopy(str, offset, value, index, len);
count += len;
return this;
}

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. Shiro简单配置

    注:这里只介绍Spring配置模式. 因为官方例子虽然中有更加简洁的ini配置形式,但是使用ini配置无法与spring整合.而且两种配置方法一样,只是格式不一样. 涉及的jar包 核心包shiro- ...

  2. Power of Two

    Given an integer, write a function to determine if it is a power of two. bool isPowerOfTwo(int n) { ...

  3. IOS开发之路三(XML解析之KissXML的使用)

    最近再做一个项目需要用到xml的解析.今天查了一些资料自己做了一个小demo.纯OC没有界面.. 在IOS平台上进行XML文档的解析有很多种方法,在SDK里面有自带的解析方法,但是大多情况下都倾向于用 ...

  4. activemq spring 配置

    Apache ActiveMQ是最流行和最强大的开源消息集成模式服务器.Apache ActiveMQ是速度快,支持多跨语言的客户端和协议,带有易于使用企业集成模式和许多先进的功能在充分支持JMS 1 ...

  5. SYS_CONTEXT 详细用法

    SELECT SYS_CONTEXT ('USERENV', 'TERMINAL') terminal,        SYS_CONTEXT ('USERENV', 'LANGUAGE') lang ...

  6. php中二维数组如何使用

    最近需要使用PHP中的二维数组,就用一个简单的例子来说明PHP中二数组是如何使用 <?php $a=array('a','b','c'); $c=array('a1','b1','c1'); $ ...

  7. Android系统--Binder系统具体框架分析(二)Binder驱动情景分析

    Android系统--Binder系统具体框架分析(二)Binder驱动情景分析 1. Binder驱动情景分析 1.1 进程间通信三要素 源 目的:handle表示"服务",即向 ...

  8. Go 语言结构体

    Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比如保存图书馆的书籍记录,每 ...

  9. I2S接口介绍

    I2S接口介绍一.I2S协议介绍 I2S协议作为音频数据传输协议,由Philips制定.该协议由三条数据线组成:1.SCLK:串行时钟,频率= 2 * 采样频率 * 采样位数.2.WS:字段(声道)选 ...

  10. 基于python的接口测试框架设计(二)配置一些参数及文件

    基于python的接口测试框架设计(二)配置一些参数及文件 我这里需要基于我的项目配置的主要是登陆参数.以及baseURL ,把这些放在单独的文件里  毕竟导入的时候方便了一些 首先是url 图略 建 ...