Java基础——String/StringBuilder/StringBuffer的区别
1. String
public final class String implements java.io.Serializable, Comparable<String>, Charsequence {
...
private final char[] value;
...
}
String x = "ab";
x += "cd";
a. JDK 1.8之前,需要三块内存完成操作,一是原来的"ab"字符串内存,一是新拼接来的"cd"字符串内存,一是拷贝两个字符串拼接在一起的新的String对象的字符串的内存;
b. JDK 1.8之后,编译器会将"+"字符串拼接操作根据需要编译成StringBuilder或者StringBuffer来处理。
String内部是一个final char[]存储的,被初始化后就不能改变这个数组,对String重新赋值实质上是在heap中重新创建String对象
2. StringBuilder
public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, Charsequence {
}
StringBuilder的数据是存储在一个char[]中,再不断调用append或者delete方法来增加或删除字符串
StringBuilder的append方法最终调用的是父类AbstractStringBuilder的append方法
详细添加步骤见下面注释
abstract class AbstractStringBuilder implements Appendable, CharSequence {
char[] value;
...
public AbstractStringBuilder append(String str) {
if (str == null) // append空字串处理
return appendNull();
// 计算要添加的字串长度
int len = str.length();
// 确保char数组的容量足够,对数组扩容,
// 实质是调用Array.copyOf把原来的字串拷贝到新的长度的char[]中
ensureCapacityInternal(count + len);
// 将需要append的字符串拷贝到新的value[]的末端
str.getChars(0, len, value, count);
// 更新char[]长度
count += len;
return this;
}
}
3. StringBuffer
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
// 在toString()时做了优化,如果这个临时的数组不为空就直接使用此数组,
// 一旦修改(增删字符)操作,都会被置空,并等下一次toString为它赋值,
// 在未修改的情况下再次toString将提高效率
private transient char[] toStringCache;
...
}
- 附:关于transient修饰符(字面意思为临时的)
1. 被此修饰符修饰后,变量将不是对象持久化的一部分,被序列化后无法访问(即transient变量不能被序列化);
2. 只能修饰类的成员变量和静态变量,不能修饰局部变量、方法、类,存在这种修饰的变量的类必须实现Serializable接口;
3. transient变量不能被反序列化(很好理解,本身不能被序列化,序列化后再反序列化自然不能得到之前的值了)
所以这个临时的变量就是在序列化前可用,序列化后,序列化再反序列化都不可用了。
StringBuffer与StringBuilder的区别是:
- StringBuffer在创建时,自带了长度16,有初始字符串也会在字串长度基础上加16
- StringBuffer是线程安全的,方法都是同步方法,适用于多线程共享的变量,在性能上为了保证同步会有所牺牲。