类
abstract class AbstractStringBuilder implements Appendable, CharSequence
抽象类,实现列Appendable和CharSequence
属性
value
char[] value;
该值用于字符存储。没加final这也是为什么StringBuffer、StringBuilder说是可变的原因
count
int count
计数是使用的字符数
MAX_ARRAY_SIZE
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
当前value数组的最大容量
构造方法
AbstractStringBuilder
AbstractStringBuilder() {
}
这个无参数构造函数对于子类的序列化是必需的。
AbstractStringBuilder(int capacity)
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
创建指定容量的AbstractStringBuilder。
方法&函数
length()
public int length() {
return count;
}
返回长度(字符数)
capacity()
public int capacity() {
return value.length;
}
返回当前容量。容量是可用于新插入字符的存储量,超过该容量将发生分配。
ensureCapacity(int minimumCapacity)
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)
ensureCapacityInternal(minimumCapacity);
}
这和value数组扩容有关系。如果当前数组小于该参数指定的容量,那么就发生扩容。(PS:还是调用了 ensureCapacityInternal 方法)
ensureCapacityInternal(int minimumCapacity)
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
用的是Arrays.copyOf这个方法扩容数组。
newCapacity(int minCapacity)
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
就是返回当前需要扩容的容量。 如果新的容量小于0或者 大于最大扩容量就调用 hugeCapacity(minCapacity)方法
PS:关于 << 运算符号,可以理解为前数乘以2的后数次方
hugeCapacity(int minCapacity)
private int hugeCapacity(int minCapacity) {
//如果扩容量大于Integer.MAX_VALUE那么就抛异常。
if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > MAX_ARRAY_SIZE)
? minCapacity : MAX_ARRAY_SIZE;
}
trimToSize()
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
}
}
尝试减少用于字符序列的存储空间。 如果缓冲区大于保持其当前字符序列所需的缓冲区,则可以调整其大小以提高空间效率。
setLength(int 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;
}
设置字符序列的长度。 序列更改为新的字符序列,其长度由参数指定。
解释片段
Arrays.fill(value, count, newLength, '\0');
fill方法:从count开始,到newLength结束填充 指定的char值(这里是'\0')到value数组里面去
charAt(int index)
public char charAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
}
返回指定索引处的char值
codePointAt(int index)
public int codePointAt(int index) {
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointAtImpl(value, index, count);
}
返回指定索引处的字符(Unicode代码点)。索引引用char值
codePointBefore(int index)
public int codePointBefore(int index) {
int i = index - 1;
if ((i < 0) || (i >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointBeforeImpl(value, index, 0);
}
返回指定索引前的Unicode代码点。
codePointCount
public int codePointCount(int beginIndex, int endIndex) {
if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
throw new IndexOutOfBoundsException();
}
return Character.codePointCountImpl(value, beginIndex, endIndex-beginIndex);
}
返回此序列的指定文本*范围内的Unicode代码点数
getChars(int srcBegin, int srcEnd, char[] dst, int 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);
}
这是一个从对象的value数字里面吧指定字符复制到目标数组的方法。
srcBegin 复制value数组的启始位置
srcEnd 复制value数组的结束位置
dst 复制的指定数组
dstBegin 指定数字的起始复制位置
setCharAt(int index, char ch)
public void setCharAt(int index, char ch) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
value[index] = ch;
}
这个就不解释啦
结下了我们来看看append方法然后实现
append(String str)
public AbstractStringBuilder append(String str) {
//判读str是不是null
if (str == null)
// appendNull就是在该value数字的后面加上一个null字符串
return appendNull();
//获取str字符串的长度
int len = str.length();
//调用这个方法是为了看看要不要扩容
ensureCapacityInternal(count + len);
//调用字符串的grtChars方法把 str字符串中的value数字拷贝到该对象的value数字中
str.getChars(0, len, value, count);
//count 增加对于长度
count += len;
//返回apppend后的该对象
return this;
}
就解释这个一个,其他的append套路都一样,只是参数不同而已
append(CharSequence s, int start, int end)
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
count += len;
//返回该对象
return this;
}
其他的append方法就不解析啦哈,那些我相信对于你已经没有啥太大的难度啦。加油!!
append(int i)
public AbstractStringBuilder append(int i) {
//如果 i等于Integer.MIN_VALUE 那么久直接添加该值对应的字符串。
// 这样干的原因是因为和int取值范围有关
if (i == Integer.MIN_VALUE) {
append("-2147483648");
return this;
}
//获得该int类型的长度
int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
: Integer.stringSize(i);
//当添加完该int值后新字符串的长度
int spaceNeeded = count + appendedLength;
//通知扩容方法,是否进行扩容
ensureCapacityInternal(spaceNeeded);
//调用Integer.getChar方法把i的转换为字符,复制到 value数字里面
Integer.getChars(i, spaceNeeded, value);
//刷新当前字符数
count = spaceNeeded;
return this;
}
appendNull()
private AbstractStringBuilder appendNull() {
int c = count;
// 如果加上null以后是否需要扩容
ensureCapacityInternal(c + 4);
final char[] value = this.value;
//添加null字符串
value[c++] = 'n';
value[c++] = 'u';
value[c++] = 'l';
value[c++] = 'l';
// 把现在的长度赋值给count
count = c;
return this;
}
delete(int start, int end)
public AbstractStringBuilder delete(int start, int end) {
if (start < 0)
//开始位置小于0抛异常
throw new StringIndexOutOfBoundsException(start);
if (end > count)
//结束位置大于字符数组中的字符总数,那么就最多只能给截到最后一位
end = count;
if (start > end)
//开始位置大于结束位置报错
throw new StringIndexOutOfBoundsException();
//计算要删除字符的总数
int len = end - start;
if (len > 0) {
// 使用arraycopy方法把删除位置后的字符覆盖被删除位置上的字符
System.arraycopy(value, start+len, value, start, count-end);
//删除后的字符总数重新计算
count -= len;
}
// 返回该对象本身
return this;
}
deleteCharAt(int index)
public AbstractStringBuilder deleteCharAt(int index) {
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
System.arraycopy(value, index+1, value, index, count-index-1);
count--;
return this;
}
删除指定位置的 字符
replace(int start, int end, String str)
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);
/**
* src:源数组;
srcPos:源数组要复制的起始位置;
dest:目的数组;
destPos:目的数组放置的起始位置;
length:复制的长度。
注意:src and dest都必须是同类型或者可以进行转换类型的数组.
*/
System.arraycopy(value, end, value, start + len, count - end);
//把str字符串复制到value数组中,从start中开始向后一个一个字符的复制
str.getChars(value, start);
//从新设置当前的count
count = newCount;
return this;
}
substring(int start, int end)
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);
}
截取指定位置字符。返回字符串。
insert(int index, char[] str, int offset, int len)
public AbstractStringBuilder insert(int offset, char[] str) {
//超出范围抛异常
if ((offset < 0) || (offset > length()))
throw new StringIndexOutOfBoundsException(offset);
//获取当前str数组的长度
int len = str.length;
//通知扩容方法看看新的字符数组是否装得下
ensureCapacityInternal(count + len);
//先将原数组移动指定位置,好让str插入进来
System.arraycopy(value, offset, value, offset + len, count - offset);
//把str从指定位置插入到数组中去
System.arraycopy(str, 0, value, offset, len);
//更新count
count += len;
return this;
}
insert(int dstOffset, CharSequence s,int start, int end)
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());
//s要插入的部分长度
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;
}
AbstractStringBuilder reverse()
public AbstractStringBuilder reverse() {
//首先设为false
boolean hasSurrogates = false;
int n = count - 1;
//(n -1) >> 1 就相当于 (n - 1) / 2, n - 1的原因是因为中间那一位不需要反转
for (int j = (n-1) >> 1; j >= 0; j--) {
/**
* k 对于数组右边的字符索引
*j 对于数组左边的字符索引
*/
int k = n - j;
char cj = value[j];
char ck = value[k];
//左右位置交换
value[j] = ck;
value[k] = cj;
/*
* Character 要判断每个字符是否在
* Character.MIN_SURROGATE(\ud800)
* 和Character.MAX_SURROGATE(\udfff)之间
*/
if (Character.isSurrogate(cj) ||
Character.isSurrogate(ck)) {
hasSurrogates = true;
}
}
if (hasSurrogates) {
reverseAllValidSurrogatePairs();
}
return this;
}
至于为什么要Character.isSurrogate() 参考博客:https://www.cnblogs.com/wanlipeng/archive/2011/01/27/1946441.html