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();
在這種情況下,兩種處理方式效率差別不大
在 JDK 8 中, String 的字符串拼接操作會被編譯器自動轉換爲 StringBuilder 並調用 append 方法,由於這樣的優化方案,使得兩個類在這種情況下的處理效率差別不大;而在 JDK 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 方法。