StringBuffer与StringBuilder
StringBuffer与StringBuilder
一、相关概念
二、StringBuffer
三、String、StringBuffer、StringBuilder效率对比
一、相关概念
StringBuffer:
1.线程安全 在所有方法上都加了同步锁(synchronized) 效率低
2.可变序列
3.JDK1.0
4.char[] value 底层实现 不没有加final修饰,说明是可变
5.与StringBuilder继承了同一个父类AbstractStringBuilder
6.支持方法链
StringBuilder:
1.线程不安全 效率高
2.可变序列
3.JDK1.5
4.char[] value 底层实现 不没有加final修饰,说明是可变
5.与StringBuffer继承了同一个父类AbstractStringBuilder
6.支持方法链
二、StringBuffer与StringBuilder
StringBuffer buffer = new StringBuffer() 实例对象();//创建StringBuffer() 实例对象
1.以这种形式创建的new StringBuffer() ,StringBuffer()会通过无参构造器创建一个16大小的char数组,默认16
public StringBuffer() {
super(16);//调用父类的构造,并传入数值
}
AbstractStringBuilder(int capacity) {
value = new char[capacity]; //获取数值,创建对应数值大小的数组
}
StringBuffer buffer = new StringBuffer(13);//创建StringBuffer() 实例对象,并传入数值
1.以这种形式创建new StringBuffer(13) ,StringBuffer(13)会通过有参构造器认创建一个指定数值大小的char数组
public StringBuffer(int capacity) {
super(capacity);
}
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
StringBuffer buffer = new StringBuffer("abc");
1.以这种形式创建的new StringBuffer(“abc”); new StringBuffer(“abc”)会通过构造器创建一个“abc”的长度加16创建一个char数组
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
StringBuffer buffer = new StringBuffer("abc");
buffer.append("sds");
那么假如使用append进行字符拼接的长度大于char数组的长度怎么办?可以看一下java底层是怎么解决的。
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len); //获取原有的数据长度+append进来的数据长度
str.getChars(0, len, value, count);
count += len;
return this;
}
ensureCapacityInternal(count + len); //获取原有的数据长度+append进来的数据长度
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code //minimumCapacity==获取原有的数据长度+append进来的数据长度
if (minimumCapacity - value.length > 0) { //判断minimumCapacity-value.length()>0 如果大于说明数组容量不足,需要扩容
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2; //扩充原数组的两倍+ 2
if (newCapacity - minCapacity < 0) {//特殊情况,假设你新拼接的字符串长度太长已超过扩容后的长度,那么干脆用原有数组的长度+新数据的长度的和
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)//如果向左移超出了范围,就可能变成负的了
? hugeCapacity(minCapacity)
: newCapacity;
}
StringBuffer buffer = new StringBuffer();
buffer.append('a');
buffer.append('c');
1.使用append拼接的是字符数据,那么底层实现就是
value[0]='a'
value[1]='c'
2.具体实现就是使用count做计数
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
}
3.那么通过使用StringBuffer().length()方法获取的长度就是在获取count的值
StringBuffer buffer = new StringBuffer("abc");
System.out.println(buffer.length());//3
三、String、StringBuffer、StringBuilder效率对比
String str1 = "";
StringBuffer stringBuffer = new StringBuffer();
StringBuilder stringBuilder = new StringBuilder();
//String
long startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
str1 += i;
}
long endTime = System.currentTimeMillis();
System.out.println("String花费时间:" + (endTime - startTime));
//StringBuffer
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
stringBuffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("stringBuffer花费时间:" + (endTime - startTime));
//StringBuilder
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
stringBuilder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("stringBuilder花费时间:" + (endTime - startTime));
String花费时间:939
stringBuffer花费时间:4
stringBuilder花费时间:2
可以看出来String因为是不可变的所以每次改变都需要去常量池创建,效率最低
而StringBuffer为保证线程安全,给append加了 锁,所以效率比StringBuilder低一点
StringBuilder效率最高,可以看情况决定使用哪种