StringBuilder
StringBuilder 是一个可变的字符序列。它继承于AbstractStringBuilder,实现了CharSequence接口。StringBuffer 也是继承于AbstractStringBuilder的子类;但是,StringBuilder和StringBuffer不同,前者是非线程安全的,后者是线程安全的。
StringBuilder 和 CharSequence之间的关系图如下:
StringBuilder属性
char[] value;
int count;
可以发现StringBuilder的底层也是使用字符数组实现的。count用于表示字符数组中使用的字符个数。
StringBuilder构造方法
public StringBuilder() {
super(16);//初始化char[]大小为16
}
父类方法:
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
可以发现我们使用无参构造方法创建StringBuilder时默认初始化大小为16。
public StringBuilder(int capacity) {
super(capacity);
}
我们也可以通过设置capacity自定义初始化大小。
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
使用字符串创建StringBuilder,需要注意的是创建的StringBuilder大小是str,length()+16。
StringBuilder strb = new StringBuilder("hello");
System.out.println(strb.capacity());//21
append()方法
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
最终调用的都是append(String str)方法:
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);//确认容量
str.getChars(0, len, value, count);
count += len;
return this;
}
这里需要注意的是,如果传入的字符串为null,那么会调用appendNull()方法,这个方法底层会添加’n’,‘u’,‘l’,'l’四个字符。
StringBuilder strb = new StringBuilder("hello");
strb.append("world");
strb.append(new A(100));
String str2 =null;
strb.append(str2);
System.out.println(strb);//helloworld100null
ensureCapacityInternal(count + len)方法
在调用append方法时总会使用此方法确认容量,它传入当前StringBuilder中已使用的容量(count)和待添加的String的长度(len)之和,这是StringBuilder所需要的最小容量。
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,newCapacity(minimumCapacity));
}
}
value.length表示的是当前StringBuilder中字符数组全部容量。如果添加字符串后所需容量大于当前StringBuilder的字符数组容量,那么就需要新开辟空间。
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;//初步设置,newCapacity为原来空间的2倍+2(这可能会导致溢出)
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;//如果还是不够大,直接将newCapacity设置为count + len
}
//newCapacity <= 0说明溢出了
//MAX_ARRAY_SIZE - newCapacity < 0说明申请的空间大于设定的最大array大小(Integer.MAX_VALUE-8)
//如果以上两个满足一个则去执行hugeCapacity()方法
//如果minCapacity > Integer.MAX_VALUE则抛出OutOfMemoryError异常
//如果MIN_ARRAY_SIZE < minCapacity则设置为minCapacity,否则设置为MAX_ARRAY_SIZE
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)? hugeCapacity(minCapacity) : newCapacity;
}
处理可以往StringBuilder中添加String和Object,还可以添加许多类型的数据,注意添加布尔类型时是添加’t’,‘r’,‘u’,‘e’和’f’,‘a’,‘l’,‘s’,'e’字符。
同时支持添加字符数组中的一部分内容。
@Override
public StringBuilder append(char[] str, int offset, int len) {
super.append(str, offset, len);
return this;
}
delete()方法
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;
}
有了添加,必然少不了删除。我们可以删除StringBuilder中的部分字符,我们可以发现底层就是讲end后的字符全部拷贝到了start后而已。
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);
System.arraycopy(value, end, value, start + len, count - end);
str.getChars(value, start);
count = newCount;
return this;
}
可以使用replace方法对StringBuilder中的部分进行替换,并且替换字符串的长度可以大于替换部位的长度。底层依旧使用数组拷贝。
其他大部分方法都是大同小异或者使用了String类的方法,感兴趣可以自行查看。
注意length()和capacity()
调用length()方法返回的是字符数组中字符的数目,调用capacity()方法返回的是字符数组容量,与多少字符无关。
文章同步至【个人站】