StringBuffer和StringBuilder都继承自AbstractStringBuilder这个类,而AbstractStringBuilder和String都继承自Object这个类。
String是不可变类,而StringBuffer, StringBuilder是可变类,String中的value[]字符数组是private的,不可以修改
只是StringBuffer 中的方法大都采用了 synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是线程不安全的。
在单线程程序下,StringBuilder效率更快,因为它不需要加锁,不具备多线程安全,而StringBuffer则每次都需要判断锁,效率相对更低
使用append()方法在字符串后面追加东西的时候,如果长度超过了该字符串存储空间大小了就需要进行扩容:构建新的存储空间更大的字符串,将旧的复制过去;再进行字符串append添加的时候,会先计算添加后字符串大小,传入一个方法:ensureCapacityInternal 这个方法进行是否扩容的判断,需要扩容就调用expandCapacity方法进行扩容
尝试将新容量扩为大小变成2倍+2 判断一下 容量如果不够,直接扩充到需要的容量大小
1.使用append算法
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
2.父类append
public AbstractStringBuilder append(String str) {
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
3.ensureCapacityInternal()
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code:判断是否需要扩容
if (minimumCapacity - value.length > 0)
expandCapacity(minimumCapacity);
}
4.expandCapacity
void expandCapacity(int minimumCapacity) {
if (newCapacity - minimumCapacity < 0)
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);
}
5.Arrays.copyOf(value, newCapacity)
//copyOf方法用于创建一个新数组,新数组的长度是扩容后的长度,并将原来的值复制到新的数组
public static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
6.void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)
//把新字符串拷贝到原字符串便宜dstBegin处,也就是拼接
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
String a = new String("test");
for(int i = 0; i<1000;i++)
{
a+=i;
}
在用a+=i连接字符串时候,每连接一次就会在堆内新分配一个内存空间新建一个stringbuffer对象来连接,如果单线程的话就要创建1002个对象(“test”一个对象,string a一个对象,1000个连接字符串时候产生的对象),在单线程情况下可能看不出影响,但如果在服务器端运行,如果很多请求,对应着很多线程就会造成创建很多对象。
解决方法:尽量使用stringbuffer中的string.append()来连接字符串。
String a = "a"+"b"+"c";
这种情况下用string,系统会自动用stringbuffer来处理,效率高
而
String a = "a";
string b = "b";
String c = "c";
String res = a+b+c;
StringBuffer res = new StringBuffer(a).append(b).append(c);
这种情况下,stringbuffer会更节省内存。