
image.png
String 是不可變量。用final關(guān)鍵字修飾字符數(shù)組來保存字符串。

image.png
StringBuffer 和 StringBuilder都繼承自AbstractStringBuilder 類,在 AbstractStringBuilder 中也是使用字符數(shù)組保存字符串char[]value 但是沒有用 final 關(guān)鍵字修飾,所以這兩種對象都是可變的。

image.png
線程安全性
String中的對象是不可變的,即常量,所以線程安全。
StringBuffer對方法或者繼承的方法加了同步鎖(synchronized),所以線程安全。
StringBuilder沒有添加同步鎖,所以不是線程安全。
性能
每次對String類型進(jìn)行改變時,都會生成一個新的String對象,然后將指針指向新的String對象。
StringBuffer 每次都會對 StringBuffer 對象本身進(jìn)行操作,而不是生成新的對象并改變對象引用。相同情況下使用 StringBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風(fēng)險。
最佳實踐
操作少量的數(shù)據(jù): 適用String
單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù): 適用StringBuilder
多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù): 適用StringBuffer
字符串常量實例
public static void main(String[] args) {
// 字符串常量,分配在常量池中,編譯器會對其進(jìn)行優(yōu)化, Interned table
// 即當(dāng)一個字符串已經(jīng)存在時,不再重復(fù)創(chuàng)建一個相同的對象,而是直接將s2也指向"hello".
String s1 = "hello";
String s2 = "hello";
// new出來的對象,分配在heap中.s3與s4雖然它們指向的字符串內(nèi)容是相同的,但是是兩個不同的對象.
// 因此==進(jìn)行比較時,其所存的引用是不同的,故不會相等
//這句話創(chuàng)建了兩個對象,一個"hello"在編譯時創(chuàng)建在常量池中,一個在運行時創(chuàng)建在堆中
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s1 == s2); // true
System.out.println(s3 == s4); // false
System.out.println(s3.equals(s4)); // true
System.out.println(s1 == s3); //false
System.out.println(s3.equals(s1)); //true
// String中equals方法已經(jīng)被重寫過,比較的是內(nèi)容是否相等.
}