JDK源码之AbstractStringBuilder类分析
一 概述
二 实现接口
AbstractStringBuilder实现了两个接口:
- Appendable
- 概述:
Appendable的实现类的对象可以附加字符序列和值.
要追加的字符应该是Unicode字符表示中描述的有效Unicode字符。注意,补充字符可能由多个16位字符值组成。
对于多线程访问不一定是安全的。线程安全是扩展和实现这个接口的类的职责。
IO流操作的写类基本都实现了这个接口,比如BufferedWriter, CharArrayWriter, CharBuffer, FileWriter等,还有StringBuffer和StringBuild也实现了这个接口 - 接口定义的方法:
- 概述:
/**
* 添加CharSequence序列到当前对象,并返回当前对象
*/
Appendable append(CharSequence csq) throws IOException;
/**
* 添加CharSequence序列参数的子序列,按照参数进行分割,到当前对象
*/
Appendable append(CharSequence csq, int start, int end) throws IOException;
/**
* 添加char值到当前对象
*/
Appendable append(char c) throws IOException;
-
CharSequence
这个接口就不多说了,表示char 值的一个可读序列(有序集合),
三 源码解析
1 属性
// 表示AbstractStringBuilder的值,可变的byte数组,jdk9之前是char数组
byte[] value;
// coder编码值,jdk9之后添加的编码标识,和String的编码coder是一样的
byte coder;
// 当前字符串已经使用的byte数组中的长度,增删改查的同时需要维护这个属性值
int count;
//空byte数组,用于无参构造器初始化,jdk9之后新增的
private static final byte[] EMPTYVALUE = new byte[0];
// 能创建数组长度的最大值
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
2 构造器
/**
* 无参构造器,vlaue默认赋值为一个长度为0的byte数组
*/
AbstractStringBuilder() {
value = EMPTYVALUE;
}
/**
* 根据参数创建指定长度的byte数组
*/
AbstractStringBuilder(int capacity) {
// 根据是否压缩标识创建单字节或者双字节存储
if (COMPACT_STRINGS) {
value = new byte[capacity];
coder = LATIN1;
} else {
value = StringUTF16.newBytesFor(capacity);//将capacity << 1 ,即创建capacity乘以2的大小byte数组
coder = UTF16;
}
}
3 基本api
//jdk11新增方法,比较大小
int compareTo(AbstractStringBuilder another) {
if (this == another) {
return 0;
}
byte val1[] = value;
byte val2[] = another.value;
int count1 = this.count;
int count2 = another.count;
if (coder == another.coder) {
return isLatin1() ? StringLatin1.compareTo(val1, val2, count1, count2)
: StringUTF16.compareTo(val1, val2, count1, count2);
}
return isLatin1() ? StringLatin1.compareToUTF16(val1, val2, count1, count2)
: StringUTF16.compareToLatin1(val1, val2, count1, count2);
}
//返回当前字符串实际的长度
@Override
public int length() {
return count;
}
//返回当前字符所占用byte数组的长度, >= length()
public int capacity() {
return value.length >> coder;
}
//确保当前value的数组长度至少等于指定的参数
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0) {
ensureCapacityInternal(minimumCapacity);
}
}
private void ensureCapacityInternal(int minimumCapacity) {
// 防止append的时候数组越界
int oldCapacity = value.length >> coder;
if (minimumCapacity - oldCapacity > 0) { //参数 > 当前byte数组长度
// 创建新长度大小的byte数组,并将value值进行copy,重新赋值给当前value
value = Arrays.copyOf(value,
newCapacity(minimumCapacity) << coder);
}
}
/**
* 判断给定参数是否溢出或者小于0,并返回合理的数组长度
*/
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder;
int newCapacity = (oldCapacity << 1) + 2;
//每次扩容,最少扩大原来的2倍+2
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
// 验证扩容值是否溢出
return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
//越界检查.是否超过最大值
private int hugeCapacity(int minCapacity) {
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
int UNSAFE_BOUND = Integer.MAX_VALUE >> coder;
if (UNSAFE_BOUND - minCapacity < 0) { // overflow
throw new OutOfMemoryError();
}
return (minCapacity > SAFE_BOUND)
? minCapacity : SAFE_BOUND;
}
//如果编码是Latin,则byte数组扩容为原来两倍,并将原有的值按双字节存储,编码改为UTF16
private void inflate() {
if (!isLatin1()) {
return;
}
byte[] buf = StringUTF16.newBytesFor(value.length);
StringLatin1.inflate(value, 0, buf, 0, count);
this.value = buf;
this.coder = UTF16;
}
//如果value数组的容量有多余的,那么就把多余的全部都释放掉
public void trimToSize() {
int length = count << coder; //实际使用了的长度
if (length < value.length) { // byte数组长度
value = Arrays.copyOf(value, length);
}
}
/**
* 强制增大实际长度count的大小,容量如果不够就用 expandCapacity()扩大;
* 将扩大的部分全部用’\0’(ASCII码中的null)来初始化
*/
public void setLength(int newLength) {
if (newLength < 0) {
throw new StringIndexOutOfBoundsException(newLength);
}
ensureCapacityInternal(newLength);
if (count < newLength) {
if (isLatin1()) {
//使用null填充
StringLatin1.fillNull(value, count, newLength);
} else {
StringUTF16.fillNull(value, count, newLength);
}
}
count = newLength;
}
// 抽象方法,需要子类自己实现
@Override
public abstract String toString();
4 增(append)
/**
* 添加Object,实际是把对象转为String,调用添加String方法
*/
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
/**
* 添加String
*/
public AbstractStringBuilder append(String str) {
if (str == null) {
return appendNull();
}
int len = str.length();
//对 byte数组扩容,确保长度大于 count+len
ensureCapacityInternal(count + len);
//讲str追加到byte数组中
putStringAt(count, str);
count += len; //修改实际占用长度
return this;
}
//添加 StringBuffer
public AbstractStringBuilder append(StringBuffer sb) {
return this.append((AbstractStringBuilder)sb);
}
/**
* jdk1.8新加的方法,逻辑跟添加String是一样的
*/
AbstractStringBuilder append(AbstractStringBuilder asb) {
if (asb == null) {
return appendNull();
}
int len = asb.length();
ensureCapacityInternal(count + len);
if (getCoder() != asb.getCoder()) {
inflate();
}
asb.getBytes(value, count, coder);
count += len;
return this;
}
// 添加 CharSequence,实现Appendable接口的方法
@Override
public AbstractStringBuilder append(CharSequence s) {
if (s == null) {
return appendNull();
}
if (s instanceof String) {
return this.append((String)s);
}
if (s instanceof AbstractStringBuilder) {
return this.append((AbstractStringBuilder)s);
}
return this.append(s, 0, s.length());
}
// 添加字符串 "null"
private AbstractStringBuilder appendNull() {
ensureCapacityInternal(count + 4);
int count = this.count;
byte[] val = this.value;
if (isLatin1()) {
val[count++] = 'n';
val[count++] = 'u';
val[count++] = 'l';
val[count++] = 'l';
} else {
count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l');
}
this.count = count;
return this;
}
//指定位置添加 s
@Override
public AbstractStringBuilder append(CharSequence s, int start, int end) {
if (s == null) {
s = "null";
}
checkRange(start, end, s.length());
int len = end - start;
ensureCapacityInternal(count + len);
appendChars(s, start, end);
return this;
}
// 添加插入数组
public AbstractStringBuilder append(char[] str) {
int len = str.length;
ensureCapacityInternal(count + len);
appendChars(str, 0, len);
return this;
}
/**
* 添加插入数组, 指定开始位置和添加的长度
*/
public AbstractStringBuilder append(char str[], int offset, int len) {
int end = offset + len;
checkRange(offset, end, str.length);
ensureCapacityInternal(count + len);
appendChars(str, offset, end);
return this;
}
// 添加 'true' 或者 'false'
public AbstractStringBuilder append(boolean b) {
ensureCapacityInternal(count + (b ? 4 : 5));
int count = this.count;
byte[] val = this.value;
if (isLatin1()) {
if (b) {
val[count++] = 't';
val[count++] = 'r';
val[count++] = 'u';
val[count++] = 'e';
} else {
val[count++] = 'f';
val[count++] = 'a';
val[count++] = 'l';
val[count++] = 's';
val[count++] = 'e';
}
} else {
if (b) {
count = StringUTF16.putCharsAt(val, count, 't', 'r', 'u', 'e');
} else {
count = StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e');
}
}
this.count = count;
return this;
}
//添加unicode代码点
public AbstractStringBuilder appendCodePoint(int codePoint) {
if (Character.isBmpCodePoint(codePoint)) {
return append((char)codePoint);
}
return append(Character.toChars(codePoint));
}
// 添加 char
@Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
if (isLatin1() && StringLatin1.canEncode(c)) {
value[count++] = (byte)c;
} else {
if (isLatin1()) {
inflate();
}
StringUTF16.putCharSB(value, count++, c);
}
return this;
}
// 添加 int,以下都是添加number
public AbstractStringBuilder append(int i) {
int count = this.count;
int spaceNeeded = count + Integer.stringSize(i);
ensureCapacityInternal(spaceNeeded);
if (isLatin1()) {
Integer.getChars(i, spaceNeeded, value);
} else {
StringUTF16.getChars(i, count, spaceNeeded, value);
}
this.count = spaceNeeded;
return this;
}
public AbstractStringBuilder append(long l) {
int count = this.count;
int spaceNeeded = count + Long.stringSize(l);
ensureCapacityInternal(spaceNeeded);
if (isLatin1()) {
Long.getChars(l, spaceNeeded, value);
} else {
StringUTF16.getChars(l, count, spaceNeeded, value);
}
this.count = spaceNeeded;
return this;
}
public AbstractStringBuilder append(float f) {
FloatingDecimal.appendTo(f,this);
return this;
}
public AbstractStringBuilder append(double d) {
FloatingDecimal.appendTo(d,this);
return this;
}
/**
* 在 index位置插入 char数组的一部分,这部分从是[ offset,offset + len )
*/
public AbstractStringBuilder insert(int index, char[] str, int offset,
int len)
{
checkOffset(index, count);
checkRangeSIOOBE(offset, offset + len, str.length);
ensureCapacityInternal(count + len);
shift(index, len);
count += len;
putCharsAt(index, str, offset, offset + len);
return this;
}
/**
* 在 offset位置,插入 obj,其他像int,boolean 都是类似的用String.valueOf转然后调用插入String方法
*/
public AbstractStringBuilder insert(int offset, Object obj) {
return insert(offset, String.valueOf(obj));
}
public AbstractStringBuilder insert(int offset, String str) {
checkOffset(offset, count);
if (str == null) {
str = "null";
}
int len = str.length();
ensureCapacityInternal(count + len);
shift(offset, len);
count += len;
putStringAt(offset, str);
return this;
}
5 删
/**
* 删除指定位置的字符
*/
public AbstractStringBuilder delete(int start, int end) {
int count = this.count;
if (end > count) {
end = count;
}
checkRangeSIOOBE(start, end, count);
int len = end - start;
if (len > 0) {
shift(end, -len); //调用System.arraycopy 方法
this.count = count - len;
}
return this;
}
/**
* 删除指定位置的字符
*/
public AbstractStringBuilder deleteCharAt(int index) {
checkIndex(index, count);
shift(index + 1, -1); //删除 index index+1 位置的字符
count--;
return this;
}
// 将value从offset开始复制 count-offset个值,从 offset+n 开始重新赋值给value, 即删减 n 个字符
private void shift(int offset, int n) {
System.arraycopy(value, offset << coder,
value, (offset + n) << coder, (count - offset) << coder);
}
6 改
/**
* 用字符串str替换掉value[]数组的[start,end)部分
*/
public AbstractStringBuilder replace(int start, int end, String str) {
int count = this.count;
if (end > count) {
end = count;
}
checkRangeSIOOBE(start, end, count);
int len = str.length();
int newCount = count + len - (end - start);
ensureCapacityInternal(newCount);//扩容
shift(end, newCount - count);// 从指定end处开始,删除或者增加 newCount - count个值
this.count = newCount;
putStringAt(start, str); //从start开始添加字符
return this;
}
//截取子字符串
public String substring(int start) {
return substring(start, count);
}
public String substring(int start, int end) {
checkRangeSIOOBE(start, end, count);
if (isLatin1()) {
return StringLatin1.newString(value, start, end - start);
}
return StringUTF16.newString(value, start, end - start);
}
/**
* 在指定index位置设置 char值
*/
public void setCharAt(int index, char ch) {
checkIndex(index, count);
if (isLatin1() && StringLatin1.canEncode(ch)) {
value[index] = (byte)ch;
} else {
if (isLatin1()) {
inflate();
}
StringUTF16.putCharSB(value, index, ch);
}
}
/**
* 将value给倒序存放(注意改变的就是本value,而不是创建了一个新的AbstractStringBuilder然后value为倒序)
*/
public AbstractStringBuilder reverse() {
byte[] val = this.value;
int count = this.count;
int coder = this.coder;
int n = count - 1;
if (COMPACT_STRINGS && coder == LATIN1) {
for (int j = (n-1) >> 1; j >= 0; j--) {
int k = n - j;
byte cj = val[j];
val[j] = val[k];
val[k] = cj;
}
} else {
StringUTF16.reverse(val, count);
}
return this;
}
7 查
/**
* 获取下标为index的char字符
*/
@Override
public char charAt(int index) {
checkIndex(index, count);
if (isLatin1()) {
return (char)(value[index] & 0xff);
}
return StringUTF16.charAt(value, index);
}
/**
* 获取index位置的unicode代码单位
*/
public int codePointAt(int index) {
int count = this.count;
byte[] value = this.value;
checkIndex(index, count);
if (isLatin1()) {
return value[index] & 0xff;
}
return StringUTF16.codePointAtSB(value, index, count);
}
/**
* 将value[]的 [srcBegin, srcEnd) 拷贝到 dst[]数组的desBegin开始处
*/
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
{
checkRangeSIOOBE(srcBegin, srcEnd, count); // compatible to old version
int n = srcEnd - srcBegin;
checkRange(dstBegin, dstBegin + n, dst.length);
if (isLatin1()) {
StringLatin1.getChars(value, srcBegin, srcEnd, dst, dstBegin);
} else {
StringUTF16.getChars(value, srcBegin, srcEnd, dst, dstBegin);
}
}
//在value[]中找字符串str,若能找到,返回第一个字符串的第一个字符的下标
public int indexOf(String str) {
return indexOf(str, 0);
}
//从fromIndex开始,在value[]中找字符串str,若能找到,返回第一个字符串的第一个字符的下标
public int indexOf(String str, int fromIndex) {
return String.indexOf(value, coder, count, str, fromIndex);
}
// 从后面往前找
public int lastIndexOf(String str) {
return lastIndexOf(str, count);
}
// 从后面往前找
public int lastIndexOf(String str, int fromIndex) {
return String.lastIndexOf(value, coder, count, str, fromIndex);
}
/**
* jdk9 新增方法,获取int流
*/
@Override
public IntStream chars() {
return StreamSupport.intStream(
() -> {
byte[] val = this.value;
int count = this.count;
byte coder = this.coder;
return coder == LATIN1
? new StringLatin1.CharsSpliterator(val, 0, count, 0)
: new StringUTF16.CharsSpliterator(val, 0, count, 0);
},
Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED,
false);
}
/**
* jdk9 新增方法,获取unicode代码点int 流
*/
@Override
public IntStream codePoints() {
return StreamSupport.intStream(
() -> {
byte[] val = this.value;
int count = this.count;
byte coder = this.coder;
return coder == LATIN1
? new StringLatin1.CharsSpliterator(val, 0, count, 0)
: new StringUTF16.CodePointsSpliterator(val, 0, count, 0);
},
Spliterator.ORDERED,
false);
}
四 总结
AbstractStringBuilder就是 可变 字符序列的一个纲领
它规定了可变字符序列应该有的行为
比如 添加字符/删除字符/更新字符/获取字符
因为可变,所以对于可变的支持,自然是必不可少的
另外,他作为String在很多方面的一个替代,必然也是提供了String的一些功能方法
否则与String API 变化巨大 也是毫无意义
因为毕竟本身就是为了描述字符序列
所以对于AbstractStringBuilder 只需要彻底理解了他作为 可变字符序列的标准接口即可
接口的两个实现StringBuffer和StringBuild大部分的功能也都是调用的父类方法!