- String 字符串常量
- StringBuilder 字符串变量(字符数组),非线程安全
- StringBuffer 字符串变量(字符数组),线程安全
String
- 不可变常量
private final char value[];
String中的字符数组value[]
定义为final
,所以String是不可变的。 - 线程安全
String是不可变的,字符串常量,所以String是线程安全的。 - 拼接
- 加号拼接
Java没有运算符重载,编译的时候检测到+
号拼接字符串,则编译器将用StringBuilder代替。
String str1 = "a";
String str2 = "b";
String str3 = "c";
String str = str1 + str2 + str3;
编译器则会转换成(避免了多次创建String对象作为中间量,但是用完就直接变成垃圾了)
String str = new StringBuilder(str1).append(str2).append(str3);
还有一种情况:
String str = "a" + "b" + "c";
编译器则直接转换成
String str = "abc";
- concat()方法
在字符串的尾部拼接指定的字符串。
- 加号拼接
public String concat(String str) {
int otherLen = str.length();
//如果指定字符串长度为0,则直接返回字符串本身。
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
//将str copy到buf[]字符数组后,并由buf[]创建新的String对象返回
str.getChars(buf, len);
return new String(buf, true);
}
void getChars(char dst[], int dstBegin) {
System.arraycopy(value, 0, dst, dstBegin, value.length);
}
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
StringBuffer
- 可变字符串
char[] value;
- 可指定字符数组长度
public StringBuffer(int capacity) {
super(capacity);
}
//初始长度为16
public StringBuffer() {
super(16);
}
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
- 线程安全
线程安全,方法都用关键字synchronized
修饰。 - toStringCache
private transient char[] toStringCache;
在任何修改字符串的方法执行前,都将该变量设为null。当调用toString()方法时,返回该缓存,如果该缓存为空,则将value
copy到该数组中。toString()方法返回的是这个数组创建的字符串。StringBuilder没有这个变量,这样子设计,可能是因为 StringBuilder 一般不会在多线程环境中使用,所以不太可能出现连接多次调用 StringBuilder.toString(),因此没有必要共享。
StringBuilder
- 可变字符串
char[] value;
- 可指定字符数组长度
跟StringBuffer一致 - 线程不安全
是轻量级StringBuffer,没有实现线程同步,效率更高,因为锁的获取和释放会带来开销。
问题 mark
public StringBuffer insert(int dstOffset, CharSequence s)
StringBuffer中没有加锁,而且也没有请toStringCache,还没搞懂。。。