Java中String、StringBuffer和StringBuilder底層實現(xiàn)深入剖析
前言
這三個類都是 java.lang 包下的字符串處理類,但它們在設(shè)計理念、內(nèi)部實現(xiàn)和適用場景上存在顯著差異。
1. 全面對比表
| 比較維度 | String | StringBuffer | StringBuilder |
|---|---|---|---|
| 可變性 | 不可變(Immutable) 內(nèi)容一旦創(chuàng)建無法修改 | 可變(Mutable) 支持原地修改 | 可變(Mutable) 支持原地修改 |
| 線程安全 | 天然線程安全(不可變對象) | 線程安全 關(guān)鍵方法(如 append、insert)加了 synchronized 鎖 | 非線程安全 無任何同步機制 |
| 性能 | 修改操作最慢(頻繁創(chuàng)建新對象) | 中等(有鎖開銷,但比 String 好) | 最高(無鎖,單線程下最優(yōu)) |
| 內(nèi)部存儲 | 底層是 final char[] value(JDK 7+)JDK 8 前是 char[],不可擴容 | 底層是 char[] value,可動態(tài)擴容 | 底層是 char[] value,可動態(tài)擴容(實現(xiàn)幾乎相同) |
| 容量擴容機制 | 無(固定長度) | 默認(rèn)容量 16,擴容時新容量 = (舊容量 * 2) + 2 | 同 StringBuffer:默認(rèn) 16,擴容時新容量 = (舊容量 * 2) + 2 |
| 內(nèi)存占用 | 每次修改產(chǎn)生新對象 + 新 char[],GC 壓力大 | 共享同一 char[],內(nèi)存高效 | 同 StringBuffer,內(nèi)存高效 |
| 字符串常量池 | 支持常量池緩存(字面量可復(fù)用) | 不支持常量池 | 不支持常量池 |
| 引入版本 | JDK 1.0 | JDK 1.0 | JDK 1.5(為單線程優(yōu)化而新增) |
| 繼承關(guān)系 | 繼承 AbstractStringBuilder,實現(xiàn) CharSequence、Serializable、Comparable | 繼承 AbstractStringBuilder,實現(xiàn) Appendable 等 | 繼承 AbstractStringBuilder,實現(xiàn) Appendable 等 |
| 方法同步 | 無需同步 | 大部分修改方法(如 append、delete)都是 synchronized | 無 synchronized |
| 典型使用場景 | 常量字符串、鍵值存儲、配置信息 | 多線程頻繁拼接(如日志記錄、共享緩沖) | 單線程頻繁拼接(如 JSON 構(gòu)建、循環(huán)拼接)——現(xiàn)代項目首選 |
| toString() 實現(xiàn) | 返回自身(緩存優(yōu)化 JDK 7+) | 新建 String 對象(調(diào)用 Arrays.copyOf) | 同 StringBuffer |
2. 底層實現(xiàn)深入剖析
String 的不可變性:
// JDK 源碼簡化版 public final class String { private final char[] value; // final 修飾,不可重新賦值 private final int hash; // 緩存 hashCode }任何“修改”操作(如
concat、replace)都會new String()并復(fù)制 char[],原對象不變。StringBuffer / StringBuilder 的可變性:
兩者都繼承自AbstractStringBuilder:abstract class AbstractStringBuilder { char[] value; // 非 final,可擴容 int count; // 當(dāng)前長度 }- append 等操作直接操作
value數(shù)組。 - 擴容時:
Arrays.copyOf創(chuàng)建更大數(shù)組,復(fù)制舊內(nèi)容。
關(guān)鍵區(qū)別:StringBuffer 的公共方法加了
synchronized:// StringBuffer 示例 public synchronized StringBuffer append(String str) { ... } // StringBuilder 示例 public StringBuilder append(String str) { ... } // 無 synchronized- append 等操作直接操作
3. 性能對比實測(循環(huán) 10 萬次拼接)
public class Test {
public static void main(String[] args) {
int times = 100000;
// String
long start = System.nanoTime();
String s = "";
for (int i = 0; i < times; i++) {
s += i;
}
System.out.println("String 用時: " + (System.nanoTime() - start) / 1e6 + " ms");
// StringBuilder
start = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < times; i++) {
sb.append(i);
}
System.out.println("StringBuilder 用時: " + (System.nanoTime() - start) / 1e6 + " ms");
// StringBuffer
start = System.nanoTime();
StringBuffer sbf = new StringBuffer();
for (int i = 0; i < times; i++) {
sbf.append(i);
}
System.out.println("StringBuffer 用時: " + (System.nanoTime() - start) / 1e6 + " ms");
}
}
典型運行結(jié)果(JDK 17,普通電腦):
- String:約 3000~5000 ms(極慢,產(chǎn)生海量臨時對象)
- StringBuilder:約 10~20 ms
- StringBuffer:約 15~30 ms(略慢于 Builder,因鎖開銷)
可見,頻繁修改時 StringBuilder 性能遙遙領(lǐng)先。
4. 編譯器優(yōu)化小秘密
單次 + 操作:JVM 會自動優(yōu)化為 StringBuilder:
String result = "a" + "b" + "c"; // 編譯后相當(dāng)于 new StringBuilder().append("a").append("b").append("c").toString()循環(huán)中 + 操作:不會跨循環(huán)優(yōu)化,仍建議手動用 StringBuilder。
5. 選擇指南(實戰(zhàn)總結(jié))
內(nèi)容幾乎不修改 → 用 String(最安全、支持常量池)。
多線程 + 頻繁修改 → 用 StringBuffer(雖慢點但安全)。
單線程 + 頻繁修改 → 必須用 StringBuilder(性能最佳,99% 場景適用)。
已知長度大 → 提前指定容量,避免擴容:
StringBuilder sb = new StringBuilder(10000); // 預(yù)分配
現(xiàn)代替代方案:復(fù)雜場景可考慮
String.join()、String.format()或流式操作,但核心拼接仍推薦 StringBuilder。
6. 常見誤區(qū)澄清
- 誤區(qū):StringBuffer 完全過時了 → 錯!在多線程共享同一緩沖時仍有價值。
- 誤區(qū):StringBuilder 線程不安全就不能用 → 大多數(shù)業(yè)務(wù)是單線程,安全使用即可。
- 誤區(qū):String 完全不能用于拼接 → 小量拼接沒問題,大量必須避免。
總結(jié)
到此這篇關(guān)于Java中String、StringBuffer和StringBuilder底層實現(xiàn)的文章就介紹到這了,更多相關(guān)Java中String、StringBuffer和StringBuilder內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java字符處理之char、String、StringBuilder和StringBuffer詳解
- Java中的char、String、StringBuilder與StringBuffer全方面解析
- Java字符串四大類之String、StringBuffer、StringBuilder、StringJoiner詳解
- Java中String、StringBuffer和StringBuilder的區(qū)別
- Java中StringBuilder與StringBuffer的區(qū)別
- Java中StringBuilder與StringBuffer使用及源碼解讀
- 淺析Java中StringBuffer和StringBuilder的使用
- 詳解Java中String,StringBuffer和StringBuilder的使用
- Java中String和StringBuffer及StringBuilder?有什么區(qū)別
- Java 中 String、StringBuffer、StringBuilder 的區(qū)別
相關(guān)文章
Java使用自定義注解+反射實現(xiàn)字典轉(zhuǎn)換代碼實例
這篇文章主要介紹了Java使用自定義注解+反射實現(xiàn)字典轉(zhuǎn)換代碼實例,注解是一種能被添加到j(luò)ava代碼中的元數(shù)據(jù),類、方法、變量、參數(shù)和包都可以用注解來修飾,注解對于它所修飾的代碼并沒有直接的影響,需要的朋友可以參考下2023-09-09
Mybatis報錯日志BindingException的解決
本文主要介紹了Mybatis報錯日志BindingException的解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
Nacos客戶端配置中心緩存動態(tài)更新實現(xiàn)源碼
這篇文章主要為大家介紹了Nacos客戶端配置中心緩存動態(tài)更新實現(xiàn)源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪2022-03-03

