AbstractStringBuilder()构造方法[OK]
int length() 获取当前对象的实际长度[OK]
int capacity() 获取当前对象的内存容量长度[OK]
void ensureCapacity() 主动触发扩容动作[OK]
void trimToSize() 释放对象中,未使用的容量内存[OK]
void setLength() 设置当前对象的实际长度,不足用’\0’填充[OK]
char charAt() 获取某个索引位置的字符[OK]
int codePointAt() 返回当前索引位置字符的ASCII值[OK]
int codePointBefore() 返回前一个索引位置字符的ASCII值[OK]
int codePointCount() 返回字符个数[OK]
int offsetByCodePoints() 返回字符个数[OK]
void getChars() 将字符从此序列复制到目标字符数组[OK]
void setCharAt() 设置某个索引位置的字符[OK]
AbstractStringBuilder append() 拼接str字符串[OK]
AbstractStringBuilder delete() 删除[start,end)位置的字符[OK]
AbstractStringBuilder appendCodePoint() 拼接ASCII码对应的int值字符 [OK]
AbstractStringBuilder deleteCharAt() 删除字符序列某个索引位置的值[OK]
AbstractStringBuilder replace() 替换某个索引范围的字符序列[OK]
AbstractStringBuilder insert() 向当前字符的某个索引位置插入字符串[OK]
AbstractStringBuilder reverse() 字符序列的反转[OK]
/**
* 这个空参构造函数,是为了让子类可以实现实例化
*/
AbstractStringBuilder() {
}
/**
* 创建一个固定容量大小的AbstractStringBuilder对象
* 1.子类StringBuilder默认容量大小为16
* 2.子类StringBuffer默认容量大小为16
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
/**
* 当前存在于对象中的字符序列长度(实际长度)
*/
@Override
public int length() {
return count;
}
/**
*1.获取当前对象的内存容量大小,默认是16
*2.扩容机制:n*2+2,详情见append方法
*3.StringBuilder、StringBuffer扩容机制相同
*/
public int capacity() {
return value.length;
}
示例:
StringBuilder sr = new StringBuilder();
//不扩容,因为参数minimumCapacity必须大于0,才进入扩展容量逻辑
sr.ensureCapacity(0);
//当前容量为16,而目标为1,不扩容。进入扩展容量逻辑,但当前容量为16,完全可以装下容量1的数据,所以不需要扩容
sr.ensureCapacity(1);
//当前容量为16,而目标为33,扩容一次,当前容量变成16*2+2=34
sr.ensureCapacity(33);
//当前容量为34,而目标为34,不扩容。进入扩展容量逻辑,但当前容量为34,完全可以装下容量34的数据,所以不需要扩容
sr.ensureCapacity(34);
//当前容量为34,而目标为35,扩容一次,当前容量变成35*2+2=70
sr.ensureCapacity(35);
System.out.println(sr.length());
System.out.println(sr.capacity());
结果:
0
70
/**
* 根据参数,主动触发扩容
* 1.首先minimumCapacity必须大于0,才进入扩容逻辑
* 2.minimumCapacity必须大于当前容量,才进入扩容逻辑
* 3.如果minimumCapacity小于等于当前容量n*2+2的值,就用默认扩容
* 4.如果minimumCapacity大于当前容量n*2+2的值,用入参进行扩容
*/
public void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > 0)//判断是否大于0
ensureCapacityInternal(minimumCapacity);
}
private void ensureCapacityInternal(int minimumCapacity) {
//判断当前参数是否大于当前容量
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2;
//比较计算后的newCapacity与minimumCapacity的大小
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
//采用Arrays.copyOf方法生成新的char[],此处是浅拷贝
value = Arrays.copyOf(value, newCapacity);
}
/**
* 释放对象中,未使用的容量内存(并不是立马释放,交给jvm处理垃圾回收)
* 样例代码:
* StringBuilder sr = new StringBuilder();
*
* System.out.println(sr.length());
* System.out.println(sr.capacity());
*
* sr.append("123456789");
* sr.trimToSize();
*
* System.out.println(sr.length());
* System.out.println(sr.capacity());
*
* 输出结果:
* 0
* 16
* 9
* 9
*/
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
}
}
/**
* 1.设置当前字符对象的实际长度,不足用'\0'填充
* 2.newLength可能触发扩容机制
* 3.注意'\0'不是空格
* 4.'\0'的ASCII值是0,空格' '字符的ASCII是32
* 5.String.trim()方法会截取掉'\0'和' '空格字符
*/
public void setLength(int newLength) {
//判断长度是否合法
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
ensureCapacityInternal(newLength);
//如果newLength大于实际存储的字符长度,则向当前字符序列的末尾填充'\0'
if (count < newLength) {
Arrays.fill(value, count, newLength, '\0');
}
count = newLength;
}
public char charAt(int index) {
//判断角标是否越界
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
return value[index];
}
/**
* 返回当前索引位置字符的ASCII值
*/
public int codePointAt(int index) {
//判断角标是否越界
if ((index < 0) || (index >= count)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointAtImpl(value, index, count);
}
static int codePointAtImpl(char[] a, int index, int limit) {
char c1 = a[index];
//判断是否是Unicode高代理代码单元
if (isHighSurrogate(c1) && ++index < limit) {
char c2 = a[index];
//判断是否是Unicode低代理代码单元
if (isLowSurrogate(c2)) {
return toCodePoint(c1, c2);
}
}
return c1;
}
/**
* 返回当前索引前一个索引位置字符的ASCII值
*/
public int codePointBefore(int index) {
int i = index - 1;
if ((i < 0) || (i >= count)) {//检查角标是否越界
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointBeforeImpl(value, index, 0);
}
static int codePointBeforeImpl(char[] a, int index, int start) {
char c2 = a[--index];//获取前一个位置的字符
//判断是否是Unicode低代理代码单元
if (isLowSurrogate(c2) && index > start) {
char c1 = a[--index];
//判断是否是Unicode高代理代码单元
if (isHighSurrogate(c1)) {
return toCodePoint(c1, c2);
}
}
return c2;
}
/**
* 返回索引位置[beginIndex,endIndex)内的有效字符数量
* 非Unicode高代理代码单元
* 非Unicode低代理代码单元
*/
public int codePointCount(int beginIndex, int endIndex) {
//判断角标是否越界
if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
throw new IndexOutOfBoundsException();
}
return Character.codePointCountImpl(value, beginIndex, endIndex-beginIndex);
}
static int codePointCountImpl(char[] a, int offset, int count) {
int endIndex = offset + count;
int n = count;
for (int i = offset; i < endIndex; ) {
//如果当前位置字符为Unicode高代理代码单元
//且下一个索引位置字符为Unicode低代理代码单元
if (isHighSurrogate(a[i++]) && i < endIndex &&
isLowSurrogate(a[i])) {
n--;//数量减一
i++;
}
}
return n;
}
/**
* 与codePointCount方法类似
* 返回索引位置[index,index+codePointOffset)内的有效字符数量
* 非Unicode高代理代码单元
* 非Unicode低代理代码单元
*/
public int offsetByCodePoints(int index, int codePointOffset) {
if (index < 0 || index > count) {
throw new IndexOutOfBoundsException();
}
return Character.offsetByCodePointsImpl(value, 0, count,
index, codePointOffset);
}
static int offsetByCodePointsImpl(char[]a, int start, int count,
int index, int codePointOffset) {
int x = index;
if (codePointOffset >= 0) {
int limit = start + count;
int i;
for (i = 0; x < limit && i < codePointOffset; i++) {
if (isHighSurrogate(a[x++]) && x < limit &&
isLowSurrogate(a[x])) {
x++;
}
}
if (i < codePointOffset) {
throw new IndexOutOfBoundsException();
}
} else {
int i;
for (i = codePointOffset; x > start && i < 0; i++) {
if (isLowSurrogate(a[--x]) && x > start &&
isHighSurrogate(a[x-1])) {
x--;
}
}
if (i < 0) {
throw new IndexOutOfBoundsException();
}
}
return x;
}
public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
int dstBegin)
{
super.getChars(srcBegin, srcEnd, dst, dstBegin);
}
/*
* 将字符从此序列复制到目标字符数组
* @param srcBegin 当前字符的索引位置
* @param srcEnd 当前字符的结束位置
* @param dst 新的char数组
* @param dstBegin 新数组开始的索引位置(一般从0开始)
*
* 底层调用的System.arraycopy方法
* /
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);
}
/**
* 设置某个索引位置的字符
* @param index 当前字符序列的索引位置
* @param ch 替换的字符
*/
public void setCharAt(int index, char ch) {
//判断角标是否越界
if ((index < 0) || (index >= count))
throw new StringIndexOutOfBoundsException(index);
value[index] = ch;
}
/**
* 拼接str字符串
* @param str 待拼接的字符串
*/
public AbstractStringBuilder append(String str) {
//判断str是否为空,如果为空,拼接null字符
if (str == null)
return appendNull();
int len = str.length();
//判断是否需要扩容
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
/**
* 删除[start,end)位置的字符
* @param start 索引开始位置(包含)
* @param 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) {
//核心逻辑,按照内存地址,对value对象进行截取,再赋值给value本身
System.arraycopy(value, start+len, value, start, count-end);
//减去中间的长度
count -= len;
}
return this;
}
/**
* 拼接ASCII码对应的int值字符
* @param codePoint拼接字符的ASCII值
*/
public AbstractStringBuilder appendCodePoint(int codePoint) {
final int count = this.count;
if (Character.isBmpCodePoint(codePoint)) {
ensureCapacityInternal(count + 1);
//将ASCII码值int转成字符97->A
value[count] = (char) codePoint;
this.count = count + 1;
} else if (Character.isValidCodePoint(codePoint)) {
ensureCapacityInternal(count + 2);
Character.toSurrogates(codePoint, value, count);
this.count = count + 2;
} else {
throw new IllegalArgumentException();
}
return this;
}
public synchronized StringBuffer deleteCharAt(int index) {
toStringCache = null;
super.deleteCharAt(index);
return this;
}
/**
* 删除某个字符序列索引位置的字符(雷同于delete方法)
* @param 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;
}
/**
* 测试样例 :
* StringBuffer sb = new StringBuffer();
String target = null;
sb.append("abcde");
sb.append(target);
sb.replace(0,1,"AAA");
* 替换某个索引范围的字符序列
* @param start 当前字符序列的开始索引位置
* @param end 当前字符序列的结束索引位置
* @param 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");
//如果end>count,默认使用count的值
if (end > count)
end = count;
//新字符串的长度
int len = str.length();
//计算替换后的字符序列大小,分析是否需要扩容
int newCount = count + len - (end - start);
ensureCapacityInternal(newCount);
//abcdnull -> abcbcdnull
System.arraycopy(value, end, value, start + len, count - end);
//AAAbcdnull
str.getChars(value, start);
count = newCount;
return this;
}
/**
* 向当前字符的某个索引位置插入字符串
* 内部实现雷同replace方法
* 1.采用System.arraycopy
* 2.采用getChars()
* @param offset 插入的索引位置
* @param str 待插入的字符串对象
*/
public AbstractStringBuilder insert(int offset, String str) {
//判断角标是否越界
if ((offset < 0) || (offset > length()))
throw new StringIndexOutOfBoundsException(offset);
//判断字符串对象是否为null
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;
}
/**
* 返回一个反转后的字符序列对象
* @since JDK1.0.2
*/
@Override
public synchronized StringBuffer reverse() {
toStringCache = null;
super.reverse();
return this;
}
public AbstractStringBuilder reverse() {
boolean hasSurrogates = false;
int n = count - 1;
//算法核心,从中间向两边扩散交换
//(n-1) >> 1 等同于 (n-1)/2
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;
}
学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:543120397 我们一起学Java!