Java中String、StringBuffer和StringBuilder底層實(shí)現(xiàn)深入剖析
前言
這三個(gè)類(lèi)都是 java.lang 包下的字符串處理類(lèi),但它們?cè)谠O(shè)計(jì)理念、內(nèi)部實(shí)現(xiàn)和適用場(chǎng)景上存在顯著差異。
1. 全面對(duì)比表
| 比較維度 | String | StringBuffer | StringBuilder |
|---|---|---|---|
| 可變性 | 不可變(Immutable) 內(nèi)容一旦創(chuàng)建無(wú)法修改 | 可變(Mutable) 支持原地修改 | 可變(Mutable) 支持原地修改 |
| 線(xiàn)程安全 | 天然線(xiàn)程安全(不可變對(duì)象) | 線(xiàn)程安全 關(guān)鍵方法(如 append、insert)加了 synchronized 鎖 | 非線(xiàn)程安全 無(wú)任何同步機(jī)制 |
| 性能 | 修改操作最慢(頻繁創(chuàng)建新對(duì)象) | 中等(有鎖開(kāi)銷(xiāo),但比 String 好) | 最高(無(wú)鎖,單線(xiàn)程下最優(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(為單線(xiàn)程優(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ǔ)、配置信息 | 多線(xiàn)程頻繁拼接(如日志記錄、共享緩沖) | 單線(xiàn)程頻繁拼接(如 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,因鎖開(kāi)銷(xiāo))
可見(jiàn),頻繁修改時(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(最安全、支持常量池)。
多線(xiàn)程 + 頻繁修改 → 用 StringBuffer(雖慢點(diǎn)但安全)。
單線(xià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. 常見(jiàn)誤區(qū)澄清
- 誤區(qū):StringBuffer 完全過(guò)時(shí)了 → 錯(cuò)!在多線(xiàn)程共享同一緩沖時(shí)仍有價(jià)值。
- 誤區(qū):StringBuilder 線(xiàn)程不安全就不能用 → 大多數(shù)業(yè)務(wù)是單線(xiàn)程,安全使用即可。
- 誤區(qū):String 完全不能用于拼接 → 小量拼接沒(méi)問(wèn)題,大量必須避免。
總結(jié)
到此這篇關(guān)于Java中String、StringBuffer和StringBuilder底層實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Java中String、StringBuffer和StringBuilder內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java中字符數(shù)組、String類(lèi)、StringBuffer三者之間相互轉(zhuǎn)換
- java stringbuffer的用法示例
- java 中String和StringBuffer與StringBuilder的區(qū)別及使用方法
- JAVA中String類(lèi)與StringBuffer類(lèi)的區(qū)別
- java_String和StringBuffer區(qū)別分析
- Java之String、StringBuffer、StringBuilder的區(qū)別分析
- Java那點(diǎn)事——StringBuffer與StringBuilder原理與區(qū)別
相關(guān)文章
Java設(shè)置session超時(shí)的幾種方式總結(jié)
這篇文章主要介紹了Java設(shè)置session超時(shí)的幾種方式總結(jié)的相關(guān)資料,需要的朋友可以參考下2017-07-07
Spring Boot Event Bus用法小結(jié)
Spring Boot Event Bus是Spring框架中事件驅(qū)動(dòng)編程的一部分,本文主要介紹了Spring Boot Event Bus用法小結(jié),感興趣的可以了解一下2023-09-09
IDEA如何將Java項(xiàng)目打包成可執(zhí)行的Jar包
在Java開(kāi)發(fā)中,我們通常會(huì)將我們的項(xiàng)目打包成可執(zhí)行的Jar包,以便于在其他環(huán)境中部署和運(yùn)行,本文將介紹如何使用IDEA集成開(kāi)發(fā)環(huán)境將Java項(xiàng)目打包成可執(zhí)行的Jar包,感興趣的朋友一起看看吧2023-07-07
Java程序圖形用戶(hù)界面設(shè)計(jì)之標(biāo)簽組件
圖形界面(簡(jiǎn)稱(chēng)GUI)是指采用圖形方式顯示的計(jì)算機(jī)操作用戶(hù)界面。與早期計(jì)算機(jī)使用的命令行界面相比,圖形界面對(duì)于用戶(hù)來(lái)說(shuō)在視覺(jué)上更易于接受,本篇精講Java語(yǔ)言中關(guān)于圖形用戶(hù)界面的標(biāo)簽組件部分2022-02-02
全解史上最快的JOSN解析庫(kù)alibaba Fastjson
這篇文章主要介紹了史上最快的JOSN解析庫(kù)alibaba Fastjson,對(duì)FastJson感興趣的同學(xué),一定要看一下2021-04-04
Feign如何使用protobuf的類(lèi)作為參數(shù)調(diào)用
這篇文章主要介紹了Feign如何使用protobuf的類(lèi)作為參數(shù)調(diào)用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringBoot項(xiàng)目創(chuàng)建單元測(cè)試的流程步驟
在日常開(kāi)發(fā)的過(guò)程中,對(duì)自己的代碼進(jìn)行單元測(cè)試是個(gè)非常重要的過(guò)程,一方面可以最小范圍的針對(duì)一個(gè)方法進(jìn)行測(cè)試,提高測(cè)試的簡(jiǎn)便性以及測(cè)試的成本,本篇文章主要是為了總結(jié)一下如何優(yōu)雅的在Springboot項(xiàng)目中使用單元測(cè)試去測(cè)試功能,需要的朋友可以參考下2024-11-11
使用java實(shí)現(xiàn)http多線(xiàn)程斷點(diǎn)下載文件(一)
Java 多線(xiàn)程斷點(diǎn)下載文件基本原理:利用URLConnection獲取要下載文件的長(zhǎng)度、頭部等相關(guān)信息,并設(shè)置響應(yīng)的頭部信息,本文將詳細(xì)介紹,需要了解更多的朋友可以參考下2012-12-12
Spring?Data?Jpa?中原生查詢(xún)?REGEXP?的使用詳解
這篇文章主要介紹了Spring?Data?Jpa?中原生查詢(xún)?REGEXP?的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12

