String,StringBuilder 以及 StringBuffer 這三個類的關係與區別一直是 Java 的經典問題,這次就來講一下關於這三個類的一些知識
一. 簡單對比
- String : 字元常量
- StringBuilder : 字元變數
- StringBuffer : 字元變數
String 屬於常量型別,被宣告為 final class,所有的屬性也都是 final 型別,因此 String 物件一旦建立,便不可更改; StringBuilder / StringBuffer 兩個類屬於變數型別,是可以更改的,它們都是為了解決字串由於拼接產生太多中間物件的問題而提供的類。
-
執行速度 StringBuilder > StringBuffer > String
-
執行緒安全: StringBuffer
-
非執行緒安全 : StringBuilder
StringBuilder 在本質上和 StringBuffer 沒有太大區別,但是由於 StringBuilder 去掉了 StringBuffer 擁有的執行緒安全部分,因此有效減少了開銷。因此,StringBuilder 是大部分情況下字串拼接操作的首選
二. String 處理字串
例一:
String s = "abcd";
s = s + "fgh";
複製程式碼
很多人作這樣的字串處理的時候會誤認為 String 型別是可變的。
但其實 JVM 處理這段程式碼的過程是這樣的:首先建立 s 物件,賦值“abcd” ,然後處理第二行程式碼時,再建立一個 s 物件,賦值 “abcdfgh”,然後將第一個 s 物件垃圾回收。
所以相當於第一個 s 沒更改過,第二個 s 是新的物件
例二:
String str = “This is only a” + “simple” + “test”;
複製程式碼
這段程式碼相當於 String str = “This is only a simple test”;
例三:
String str2 = "This is only a";
String str3 = "simple";
String str4 = "test";
String str1 = str2 +str3 + str4;
複製程式碼
這段程式碼同樣會按照例一的過程來處理
三. StringBuilder / StringBuffer 構造特性
這兩個物件在構造的過程中,首先按照預設大小申請一個字元陣列(char[]), 預設容量為 16 個字元,但如果超出,會使用 Arrays.copyOf() 成倍擴容 16,32,64, 128...,當然這樣會影響效能,因此可以在建立物件時按照需要自定義其容量
原始碼:
//預設 16 個字元
public StringBuilder() {
super(16);
}
//建構函式定義容量
public StringBuilder(int capacity) {
super(capacity);
}
複製程式碼
四. String 與 StringBuilder 處理字串拼接對比
我們都知道,進行字串拼接操作時推薦使用 StringBuilder,但是是不是什麼時候都推薦使用 StringBuilder 來代替 String 進行字串拼接?顯然不是的。
例一:
String str = "123";
String str1 = str + "456";
String str2 = new StringBuilder().append(str).append("def").toString();
複製程式碼
在這種情況下,兩種處理方式效率差別不大
在 JDK1.5 之後, String 的字串拼接操作會被編譯器自動轉換為 StringBuilder 並呼叫 append 方法,最後呼叫 StringBuilder 的 toString 方法返回一個重新建立的字串,由於這樣的優化方案,使得兩個類在這種情況下的處理效率差別不大;而在 Java 9 中,為了更加統一字串操作優化,提供了 StringConcatFactory,作為一個統一的入口,更加優化了字串拼接操作。
例二:
String str = "";
for (int i = 0; i < 1000; i++) {
str += "12345";
}
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 1000; i++) {
stringBuilder.append("12345");
}
複製程式碼
這種情況下,StringBuilder 更快
在迴圈中,每執行一次 “+”,都會建立一個 String 物件,因此會有大量物件建立和回收的消耗。
簡單來說,在迴圈中對同一個字串物件做字串拼接,優先選擇 StringBuilder
例三
String str1 = "123" + "456" + "789";
String str2 = new StringBuilder("123").append("456").append("789").toString();
複製程式碼
這種情況下,String 更快
我們都知道 String str1 = "123" + "456" + "789";
其實是等同於 String str1 = "123456789";
的,而 StringBuilder 反而需要多次呼叫 append 方法。