String,StringBuilder 以及 StringBuffer 這三個(gè)類的關(guān)系與區(qū)別一直是 Java 的經(jīng)典問題,這次就來講一下關(guān)于這三個(gè)類的一些知識
一. 簡單對比
- String : 字符常量
- StringBuilder : 字符變量
- StringBuffer : 字符變量
String 屬于常量類型痒芝,被聲明為 final class俐筋,所有的屬性也都是 final 類型,因此 String 對象一旦創(chuàng)建严衬,便不可更改澄者;
StringBuilder / StringBuffer 兩個(gè)類屬于變量類型,是可以更改的请琳,它們都是為了解決字符串由于拼接產(chǎn)生太多中間對象的問題而提供的類粱挡。
- 運(yùn)行速度 StringBuilder > StringBuffer > String
- 線程安全: StringBuffer
- 非線程安全 : StringBuilder
StringBuilder 在本質(zhì)上和 StringBuffer 沒有太大區(qū)別,但是由于 StringBuilder 去掉了 StringBuffer 擁有的線程安全部分单起,因此有效減少了開銷抱怔。因此,StringBuilder 是大部分情況下字符串拼接操作的首選
二. String 處理字符串
例一:
String s = "abcd";
s = s + "fgh";
很多人作這樣的字符串處理的時(shí)候會誤認(rèn)為 String 類型是可變的嘀倒。
但其實(shí) JVM 處理這段代碼的過程是這樣的:首先創(chuàng)建 s 對象,賦值“abcd” ,然后處理第二行代碼時(shí)测蘑,再創(chuàng)建一個(gè) s 對象灌危,賦值 “abcdfgh”,然后將第一個(gè) s 對象垃圾回收碳胳。
所以相當(dāng)于第一個(gè) s 沒更改過勇蝙,第二個(gè) s 是新的對象
例二:
String str = “This is only a” + “simple” + “test”;
這段代碼相當(dāng)于 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 構(gòu)造特性
這兩個(gè)對象在構(gòu)造的過程中,首先按照默認(rèn)大小申請一個(gè)字符數(shù)組(char[])挨约, 默認(rèn)容量為 16 個(gè)字符味混,但如果超出,會使用 Arrays.copyOf() 成倍擴(kuò)容 16诫惭,32翁锡,64, 128...,當(dāng)然這樣會影響性能夕土,因此可以在創(chuàng)建對象時(shí)按照需要自定義其容量
源代碼:
//默認(rèn) 16 個(gè)字符
public StringBuilder() {
super(16);
}
//構(gòu)造函數(shù)定義容量
public StringBuilder(int capacity) {
super(capacity);
}
四. String 與 StringBuilder 處理字符串拼接對比
我們都知道馆衔,進(jìn)行字符串拼接操作時(shí)推薦使用 StringBuilder,但是是不是什么時(shí)候都推薦使用 StringBuilder 來代替 String 進(jìn)行字符串拼接怨绣?顯然不是的角溃。
例一:
String str = "123";
String str1 = str + "456";
String str2 = new StringBuilder().append(str).append("def").toString();
在這種情況下,兩種處理方式效率差別不大
在 JDK1.5 之后篮撑, String 的字符串拼接操作會被編譯器自動轉(zhuǎn)換為 StringBuilder 并調(diào)用 append 方法减细,最后調(diào)用 StringBuilder 的 toString 方法返回一個(gè)重新創(chuàng)建的字符串,由于這樣的優(yōu)化方案赢笨,使得兩個(gè)類在這種情況下的處理效率差別不大邪财;而在 Java 9 中,為了更加統(tǒng)一字符串操作優(yōu)化质欲,提供了 StringConcatFactory树埠,作為一個(gè)統(tǒng)一的入口,更加優(yōu)化了字符串拼接操作嘶伟。
例二:
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 更快
在循環(huán)中,每執(zhí)行一次 “+”九昧,都會創(chuàng)建一個(gè) String 對象绊袋,因此會有大量對象創(chuàng)建和回收的消耗。
簡單來說铸鹰,在循環(huán)中對同一個(gè)字符串對象做字符串拼接癌别,優(yōu)先選擇 StringBuilder
例三
String str1 = "123" + "456" + "789";
String str2 = new StringBuilder("123").append("456").append("789").toString();
這種情況下,String 更快
我們都知道 String str1 = "123" + "456" + "789";
其實(shí)是等同于 String str1 = "123456789";
的蹋笼,而 StringBuilder 反而需要多次調(diào)用 append 方法展姐。