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

