1️⃣类定义
AbstractStringBuilder是StringBuilder和StringBuffer的父类,包含字符串操作(修改、插入、追加等)的实现逻辑,子类根据各自需求对方法调用做同步处理,本身是线程不安全的。
abstract class AbstractStringBuilder implements Appendable, CharSequence
由于实现了CharSequence接口,所以StringBuilder和StringBuffer的实例可以直接赋值给CharSequence;
Appendable能够被追加 char 序列和值的对象。如果某个类的实例打算接收来自 Formatter 的格式化输出,那么该类必须实现 Appendable 接口。
2️⃣变量
/**
* 保存字符串的数组.
*/
char[] value;
/**
* 记录字符长度.
*/
int count;
3️⃣构造器
/**
* 无参构造方法,用于序列化和子类.
*/
AbstractStringBuilder() {
}
/**
* 指定容量构造字符串数组.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
4️⃣方法
长度相关的方法
/**
* 返回当前字符长度.
*/
@Override
public int length() {
return count;
}
/**
* 返回当前容量(容量是存储容量).
*/
public int capacity() {
return value.length;
}
扩容相关的方法
/**
* 确保最小期望容量至少大于0,如果大于0则调用ensureCapacityInternal().
*/
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
/**
* 包含参数检查,最小容量不得小于已有字符串数组长度,没有同步特性.
*/
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
/**
* 要分配的数组的最大大小.此属性调用了Integer中的常量作为参数
* @Native public static final int MAX_VALUE = 0x7fffffff;
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 返回的容量至少与给定的最小容量相同.
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
// 如果创建的容器容量小于最小期望的容量,则将最小期望容量赋值给newCapacity
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
// 如果新容器的容量小于等于0或者要分配的数组的最大大小与新容器的差值小于0则调用hugeCapacity(),反之使用当前容器
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
/**
* 创建一个巨大容量的容器,如果要分配的数组的最大大小小于传入的容量大小则抛出OutOfMemoryError异常,否则根据三元结果进行创建.
*/
private int hugeCapacity(int minCapacity) {
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
裁剪 填充
/**
*把字符串拷贝到长度刚好合适的字符数组中返回,释放原数组空间;建议
*没有特殊情况不要使用这个方法,一次超大数组的拷贝非常消耗性能
*/
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
}
}
/**
*通过添加字符'\0',令字符串长度达到newLength,仅在newLength大于数
*组内字符串长度有效。
*/
public void setLength(int newLength) {
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
ensureCapacityInternal(newLength);
if (count < newLength) {
Arrays.fill(value, count, newLength, '\0');
}
count = newLength;
}
查找
/**
* 返回指定索引值下的字符
*
* @param index
* @return
*/
@Override
public char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
}
/**
* 返回指定索引下字符的编码值
*
* @param index
* @return
*/
public int codePointAt(int index) {
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointAtImpl(value, index, count);
}
/**
* 返回指定索引前一位字符的编码值
*
* @param index
* @return
*/
public int codePointBefore(int index) {
int i = index - 1;
if ((i < 0) || (i >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointBeforeImpl(value, index, 0);
}
public int codePointCount(int beginIndex, int endIndex) {
if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
throw new IndexOutOfBoundsException();
}
return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
}
public int offsetByCodePoints(int index, int codePointOffset) {
if (index < 0 || index > count) {
throw new IndexOutOfBoundsException();
}
return Character.offsetByCodePointsImpl(value, 0, count,
index, codePointOffset);
}
/**
* 复制指定范围的字符串到给定的字符数组中
*
* @param srcBegin
* @param srcEnd
* @param dst
* @param dstBegin
*/
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) {
if (srcBegin < 0)
throw new StringIndexOutOfBoundsException(srcBegin);
if ((srcEnd < 0) || (srcEnd > count))
throw new StringIndexOutOfBoundsException(srcEnd);
if (srcBegin > srcEnd)
throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
append方法
append方法的很多重载就是靠调用getChars方法来达到尾插的目的的. 很简单, 就不提了.我们重点关注一下appendNull和append方法的bool型重载
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
count = c;
return this;
}
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;
}
substring
public String substring(int start, int end) {
if (start < 0)
throw new StringIndexOutOfBoundsException(start);
if (end > count)
throw new StringIndexOutOfBoundsException(end);
if (start > end)
throw new StringIndexOutOfBoundsException(end - start);
return new String(value, start, end - start);
}
可以看到substring底层是直接调用的new String
reverse
public AbstractStringBuilder reverse() {
boolean hasSurrogates = false;
int n = count - 1;
for (int j = (n-1) >> 1; j >= 0; j--) {
int k = n - j;
char cj = value[j];
char ck = value[k];
value[j] = ck;
value[k] = cj;
if (Character.isSurrogate(cj) ||
Character.isSurrogate(ck)) {
hasSurrogates = true;
}
}
if (hasSurrogates) {
reverseAllValidSurrogatePairs();
}
return this;
}
两个指针j和k. 关于中心对称. 从中间开始一边向两边遍历, 一边交换. 就完成了翻转.
insert以及查索引的方法也是大量的使用了重载,所以这里简单列出来大家看一下即可
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;
}
public AbstractStringBuilder insert(int offset, Object obj) {
return insert(offset, String.valueOf(obj));
}
public AbstractStringBuilder insert(int offset, String str) {
if ((offset < 0) || (offset > length()))
throw new StringIndexOutOfBoundsException(offset);
if (str == null)
str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
System.arraycopy(value, offset, value, offset + len, count - offset);
str.getChars(value, offset);
count += len;
return this;
}
public AbstractStringBuilder insert(int offset, char[] str) {
if ((offset < 0) || (offset > length()))
throw new StringIndexOutOfBoundsException(offset);
int len = str.length;
ensureCapacityInternal(count + len);
System.arraycopy(value, offset, value, offset + len, count - offset);
System.arraycopy(str, 0, value, offset, len);
count += len;
return this;
}
public AbstractStringBuilder insert(int dstOffset, CharSequence s) {
if (s == null)
s = "null";
if (s instanceof String)
return this.insert(dstOffset, (String)s);
return this.insert(dstOffset, s, 0, s.length());
}
public AbstractStringBuilder insert(int dstOffset, CharSequence s,
int start, int end) {
if (s == null)
s = "null";
if ((dstOffset < 0) || (dstOffset > this.length()))
throw new IndexOutOfBoundsException("dstOffset "+dstOffset);
if ((start < 0) || (end < 0) || (start > end) || (end > s.length()))
throw new IndexOutOfBoundsException(
"start " + start + ", end " + end + ", s.length() "
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
System.arraycopy(value, dstOffset, value, dstOffset + len,
count - dstOffset);
for (int i=start; i<end; i++)
value[dstOffset++] = s.charAt(i);
count += len;
return this;
}
public AbstractStringBuilder insert(int offset, boolean b) {
return insert(offset, String.valueOf(b));
}
public AbstractStringBuilder insert(int offset, char c) {
ensureCapacityInternal(count + 1);
System.arraycopy(value, offset, value, offset + 1, count - offset);
value[offset] = c;
count += 1;
return this;
}
public AbstractStringBuilder insert(int offset, int i) {
return insert(offset, String.valueOf(i));
}
public AbstractStringBuilder insert(int offset, long l) {
return insert(offset, String.valueOf(l));
}
public AbstractStringBuilder insert(int offset, float f) {
return insert(offset, String.valueOf(f));
}
public AbstractStringBuilder insert(int offset, double d) {
return insert(offset, String.valueOf(d));
}
public int indexOf(String str) {
return indexOf(str, 0);
}
public int indexOf(String str, int fromIndex) {
return String.indexOf(value, 0, count, str, fromIndex);
}
public int lastIndexOf(String str) {
return lastIndexOf(str, count);
}
public int lastIndexOf(String str, int fromIndex) {
return String.lastIndexOf(value, 0, count, str, fromIndex);
}
5️⃣总结
①构造器里立即初始化数组;
②扩容方式为:扩容前长度 * 2 + 2(如果插入的这个字符串太长, 导致扩容一次也无法容纳就直接把长度设置为 扩容前长度+ 插入的字符串长度 )
③大规模使用了System.arraycopy方法