Java中經常使用來處理字符串的類有三個: String, StringBuffer和StringBuilder.html
三者都繼承自CharSequence接口, 首先說明三者間主要區別安全
在Java中String對象是不可變的. 每次改變String類型的時候都會生成一個新的String對象, 而後將指針指向新的String對象.多線程
以下代碼中, str最終的值"ab"並不是str所引用對象的內容發生了變化, 而是str在執行的過程當中從新引用了另一個String對象"ab". 而且String的+操做, 會轉化成StringBuilder的append()方法來實現.app
String str = "a"; str += "b";
特別的, 若是代碼以下這樣直接拼接字符串的話, 在編譯過程當中JVM會直接優化成把str的引用指向"ab".性能
String str = "a" + "b";
StringBuffer和StringBuilder均可變, 區別在於StringBuilder是線程不安全的, 而StringBuffer的API前多了一個synchronized關鍵字, 因此StringBuffer是線程安全的. 所謂的線程安全就是在多線程中多個線程同時操做一個對象不會出現問題. 然而真實的應用場景中, 還真沒怎麼見過有多個線程輪流操做一個字符串的狀況.優化
實際上StringBuilder是在JDK 1.5中才加上的, 以前只有StringBuffer, 寫過幾年C#的我非常懷疑StringBuilder的這個命名是從C#借鑑來的. 至於爲何先有一個線程安全的StringBuffer後來再有一個線程不安全的StringBuilder, 並且從二者的命名來看你壓根區分不出哪一個是線程安全的, 我的感受這應該是一個設計失誤吧...ui
StringBuffer和StringBuilder都繼承自AbstractStringBuilder, 而AbstractStringBuilder裏有個expandCapacity方法用來擴容, 這就致使了StringBuffer和StringBuilder中另一個重要的問題, 就是初始化時的容量問題.spa
在StringBuilder中有一個char[], 初始的容量是16. 那麼問題來了, 若是要append的長度超過了16, 會發生什麼?線程
答案是會調用expandCapacity, 成倍擴容! 因此在高性能場景下StringBuilder的初始長度很重要很重要.設計
void expandCapacity(int minimumCapacity) { int newCapacity = value.length * 2 + 2; 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); }
初始長度過小擴容時會帶來時間消耗, 初始長度太大又會帶來空間消耗. 能夠參考這裏的用法來複用StringBuilder.