String 是不可變量氓鄙。用final關(guān)鍵字修飾字符數(shù)組來(lái)保存字符串扭倾。
StringBuffer 和 StringBuilder都繼承自AbstractStringBuilder 類(lèi)鄙陡,在 AbstractStringBuilder 中也是使用字符數(shù)組保存字符串char[]value 但是沒(méi)有用 final 關(guān)鍵字修飾沮协,所以這兩種對(duì)象都是可變的谦铃。
線程安全性
String中的對(duì)象是不可變的,即常量蛙紫,所以線程安全拍屑。
StringBuffer對(duì)方法或者繼承的方法加了同步鎖(synchronized),所以線程安全坑傅。
StringBuilder沒(méi)有添加同步鎖僵驰,所以不是線程安全。
性能
每次對(duì)String類(lèi)型進(jìn)行改變時(shí)唁毒,都會(huì)生成一個(gè)新的String對(duì)象蒜茴,然后將指針指向新的String對(duì)象。
StringBuffer 每次都會(huì)對(duì) StringBuffer 對(duì)象本身進(jìn)行操作浆西,而不是生成新的對(duì)象并改變對(duì)象引用粉私。相同情況下使用 StringBuilder 相比使用 StringBuffer 僅能獲得 10%~15% 左右的性能提升,但卻要冒多線程不安全的風(fēng)險(xiǎn)近零。
最佳實(shí)踐
操作少量的數(shù)據(jù): 適用String
單線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù): 適用StringBuilder
多線程操作字符串緩沖區(qū)下操作大量數(shù)據(jù): 適用StringBuffer
字符串常量實(shí)例
public static void main(String[] args) {
// 字符串常量诺核,分配在常量池中,編譯器會(huì)對(duì)其進(jìn)行優(yōu)化久信, Interned table
// 即當(dāng)一個(gè)字符串已經(jīng)存在時(shí)窖杀,不再重復(fù)創(chuàng)建一個(gè)相同的對(duì)象,而是直接將s2也指向"hello".
String s1 = "hello";
String s2 = "hello";
// new出來(lái)的對(duì)象裙士,分配在heap中.s3與s4雖然它們指向的字符串內(nèi)容是相同的入客,但是是兩個(gè)不同的對(duì)象.
// 因此==進(jìn)行比較時(shí),其所存的引用是不同的腿椎,故不會(huì)相等
//這句話(huà)創(chuàng)建了兩個(gè)對(duì)象桌硫,一個(gè)"hello"在編譯時(shí)創(chuàng)建在常量池中,一個(gè)在運(yùn)行時(shí)創(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)被重寫(xiě)過(guò)啃炸,比較的是內(nèi)容是否相等.
}