Java StringBuilder 實(shí)現(xiàn)原理全攻略
一、StringBuilder 基本概述
StringBuilder 是 Java 提供的可變字符序列類,位于 java.lang 包中,專門用于高效處理字符串的拼接和修改操作。與不可變的 String 類相比,StringBuilder 提供了更優(yōu)的性能表現(xiàn),特別是在頻繁修改字符串的場(chǎng)景下。
核心特性
- 可變性:內(nèi)部字符數(shù)組可動(dòng)態(tài)擴(kuò)展
- 非線程安全:相比 StringBuffer 有更好的性能
- 高效操作:避免創(chuàng)建大量臨時(shí) String 對(duì)象
二、StringBuilder 核心實(shí)現(xiàn)
2.1 內(nèi)部數(shù)據(jù)結(jié)構(gòu)
StringBuilder 的核心是一個(gè)可變的字符數(shù)組(char[]):
// JDK 17 中的實(shí)現(xiàn)
abstract class AbstractStringBuilder {
byte[] value; // Java 9 后改為byte[]以支持緊湊字符串
int count; // 實(shí)際使用的字符數(shù)
boolean isLatin1; // 是否Latin-1編碼
}Java 9 重大變化:為了減少內(nèi)存占用,JDK 9 將內(nèi)部實(shí)現(xiàn)從
char[]改為byte[],并引入編碼標(biāo)志位來(lái)支持緊湊字符串(Compact Strings)特性。
2.2 初始化機(jī)制
StringBuilder 提供多種構(gòu)造方法:
// 默認(rèn)構(gòu)造器(初始容量16)
StringBuilder sb1 = new StringBuilder();
// 指定初始容量
StringBuilder sb2 = new StringBuilder(100);
// 基于字符串初始化
StringBuilder sb3 = new StringBuilder("Hello");初始化時(shí)內(nèi)部數(shù)組大小計(jì)算:
- 默認(rèn)構(gòu)造器:16字符
- 指定容量:使用指定值
- 字符串初始化:字符串長(zhǎng)度 + 16
2.3 自動(dòng)擴(kuò)容機(jī)制
當(dāng)追加內(nèi)容超過(guò)當(dāng)前容量時(shí),StringBuilder 會(huì)自動(dòng)擴(kuò)容:
private void ensureCapacityInternal(int minimumCapacity) {
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value, newCapacity(minimumCapacity));
}
}
private int newCapacity(int minCapacity) {
int newCapacity = (value.length << 1) + 2; // 通常擴(kuò)容為原大小2倍+2
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}擴(kuò)容策略:
- 新容量 = (原容量 × 2) + 2
- 如果仍不足,則直接擴(kuò)容到所需大小
- 最大容量為 Integer.MAX_VALUE - 8
三、關(guān)鍵操作實(shí)現(xiàn)原理
3.1 append() 方法實(shí)現(xiàn)
append() 是 StringBuilder 最常用的方法,支持多種數(shù)據(jù)類型:
public StringBuilder append(String str) {
super.append(str);
return this;
}
// 父類 AbstractStringBuilder 中的實(shí)現(xiàn)
public AbstractStringBuilder append(String str) {
if (str == null) {
return appendNull();
}
int len = str.length();
ensureCapacityInternal(count + len);
putStringAt(count, str);
count += len;
return this;
}執(zhí)行流程:
- 檢查容量是否足夠
- 將新內(nèi)容拷貝到字符數(shù)組
- 更新字符計(jì)數(shù)
3.2 insert() 方法實(shí)現(xiàn)
public StringBuilder insert(int offset, String str) {
super.insert(offset, str);
return this;
}
// 父類實(shí)現(xiàn)
public AbstractStringBuilder insert(int offset, String str) {
if ((offset < 0) || (offset > length()))
throw new StringIndexOutOfBoundsException(offset);
if (str == null)
str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
shift(offset, len); // 移動(dòng)現(xiàn)有字符
putStringAt(offset, str);
count += len;
return this;
}特點(diǎn):
- 需要移動(dòng)現(xiàn)有字符為新內(nèi)容騰出空間
- 性能比 append() 差,特別是插入位置靠前時(shí)
3.3 delete() 方法實(shí)現(xiàn)
public StringBuilder delete(int start, int end) {
super.delete(start, end);
return this;
}
// 父類實(shí)現(xiàn)
public AbstractStringBuilder delete(int start, int end) {
int count = this.count;
if (end > count)
end = count;
if (start > end)
throw new StringIndexOutOfBoundsException();
int len = end - start;
if (len > 0) {
shift(end, -len); // 向左移動(dòng)字符
count -= len;
}
return this;
}四、性能優(yōu)化分析
4.1 與 String 拼接的對(duì)比
String 拼接示例:
String result = "";
for (int i = 0; i < 10000; i++) {
result += i; // 每次循環(huán)創(chuàng)建新String對(duì)象
}
StringBuilder 優(yōu)化:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(i); // 僅操作內(nèi)部數(shù)組
}
String result = sb.toString();
性能差異:
- String 拼接:O(n²) 時(shí)間復(fù)雜度
- StringBuilder:O(n) 時(shí)間復(fù)雜度
4.2 初始容量?jī)?yōu)化
合理設(shè)置初始容量可避免多次擴(kuò)容:
// 預(yù)估最終字符串長(zhǎng)度約為2000字符 StringBuilder sb = new StringBuilder(2000);
擴(kuò)容代價(jià):
- 分配新數(shù)組
- 拷貝原有內(nèi)容
- 丟棄舊數(shù)組(增加GC壓力)
4.3 Java 9 后的緊湊字符串優(yōu)化
JDK 9 引入的緊湊字符串特性使 StringBuilder 更高效:
- Latin-1 字符使用1字節(jié)存儲(chǔ)
- UTF-16 字符使用2字節(jié)存儲(chǔ)
- 自動(dòng)檢測(cè)和轉(zhuǎn)換編碼
五、線程安全性考慮
StringBuilder 是非線程安全的實(shí)現(xiàn),而 StringBuffer 是線程安全的版本:
// StringBuilder 的典型方法(無(wú)同步)
public StringBuilder append(String str) {
super.append(str);
return this;
}
// StringBuffer 的對(duì)應(yīng)方法(有同步鎖)
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}選擇建議:
- 單線程環(huán)境:優(yōu)先使用 StringBuilder(性能更優(yōu))
- 多線程環(huán)境:使用 StringBuffer 或外部同步
六、特殊方法解析
6.1 reverse() 實(shí)現(xiàn)
public StringBuilder reverse() {
super.reverse();
return this;
}
// 父類實(shí)現(xiàn)
public AbstractStringBuilder reverse() {
boolean hasSurrogate = false;
int n = count - 1;
for (int j = (n-1) >> 1; j >= 0; j--) {
char temp = value[j];
char temp2 = value[n - j];
if (!hasSurrogate) {
hasSurrogate = (temp >= Character.MIN_SURROGATE &&
temp <= Character.MAX_SURROGATE) ||
(temp2 >= Character.MIN_SURROGATE &&
temp2 <= Character.MAX_SURROGATE);
}
value[j] = temp2;
value[n - j] = temp;
}
if (hasSurrogate) {
reverseAllValidSurrogatePairs();
}
return this;
}特點(diǎn):
- 處理了Unicode代理對(duì)(surrogate pairs)
- 原地反轉(zhuǎn),不創(chuàng)建新數(shù)組
6.2 setLength() 實(shí)現(xiàn)
public void setLength(int newLength) {
if (newLength < 0)
throw new StringIndexOutOfBoundsException(newLength);
ensureCapacityInternal(newLength);
if (count < newLength) {
// 填充空字符
Arrays.fill(value, count, newLength, '\0');
}
count = newLength;
}用途:
- 截?cái)嘧址╪ewLength < count)
- 擴(kuò)展字符串(newLength > count)
七、與StringBuffer的關(guān)系
StringBuilder 和 StringBuffer 都繼承自 AbstractStringBuilder:

設(shè)計(jì)差異:
- StringBuffer 方法添加了 synchronized 關(guān)鍵字
- StringBuffer 有 toStringCache 字段優(yōu)化多次 toString() 調(diào)用
- StringBuilder 自 JDK 5 引入,作為 StringBuffer 的非線程安全替代
八、最佳實(shí)踐
循環(huán)拼接字符串必用 StringBuilder:
// 錯(cuò)誤示范
String result = "";
for (String part : parts) {
result += part;
}
// 正確做法
StringBuilder sb = new StringBuilder();
for (String part : parts) {
sb.append(part);
}
String result = sb.toString();預(yù)估大小減少擴(kuò)容:
// 已知大約需要200字符空間 StringBuilder sb = new StringBuilder(200);
鏈?zhǔn)秸{(diào)用:
String result = new StringBuilder()
.append("Name: ").append(name)
.append(", Age: ").append(age)
.toString();
局部使用優(yōu)于成員變量:
// 每個(gè)方法內(nèi)創(chuàng)建獨(dú)立的StringBuilder
void process() {
StringBuilder sb = new StringBuilder();
// 使用sb
}
復(fù)雜格式化考慮 String.format():
// 簡(jiǎn)單情況
String message = String.format("User %s (ID: %d) logged in", name, id);
// 非常復(fù)雜的格式化仍可用StringBuilder九、現(xiàn)代Java中的變化
JDK 9+ 的改進(jìn)
- 緊湊字符串(Compact Strings):
- 內(nèi)部存儲(chǔ)從 char[] 改為 byte[]
- 根據(jù)內(nèi)容自動(dòng)選擇 Latin-1 或 UTF-16 編碼
- 顯著減少內(nèi)存占用
- 字符串拼接優(yōu)化:
- 現(xiàn)代Java編譯器會(huì)將某些 String 拼接自動(dòng)優(yōu)化為 StringBuilder 操作
JDK 15 的文本塊(Text Blocks)
雖然與 StringBuilder 無(wú)直接關(guān)系,但文本塊減少了復(fù)雜字符串構(gòu)建的需求:
// 傳統(tǒng)方式
String html = new StringBuilder()
.append("<html>\n")
.append(" <body>\n")
.append(" <p>Hello</p>\n")
.append(" </body>\n")
.append("</html>")
.toString();
// JDK 15+
String html = """
<html>
<body>
<p>Hello</p>
</body>
</html>""";十、總結(jié)
StringBuilder 的核心價(jià)值在于:
- 高效的內(nèi)存使用:通過(guò)可變字符數(shù)組避免大量臨時(shí)對(duì)象
- 優(yōu)秀的性能表現(xiàn):O(n) 復(fù)雜度的字符串操作
- 靈活的API設(shè)計(jì):支持鏈?zhǔn)秸{(diào)用和各種數(shù)據(jù)類型
- 與時(shí)俱進(jìn):Java 9 的緊湊字符串進(jìn)一步提升了效率
理解其實(shí)現(xiàn)原理有助于:
- 編寫(xiě)更高效的字符串處理代碼
- 在合適的場(chǎng)景選擇最佳工具
- 診斷字符串相關(guān)的性能問(wèn)題
- 深入理解Java集合和數(shù)組的設(shè)計(jì)思想
到此這篇關(guān)于Java StringBuilder 實(shí)現(xiàn)原理全攻略的文章就介紹到這了,更多相關(guān)Java StringBuilder 原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)微信公眾號(hào)掃一掃
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)微信公眾號(hào)掃一掃,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04
Java中Stringbuild,Date和Calendar類的用法詳解
這篇文章主要為大家詳細(xì)介紹了Java中Stringbuild、Date和Calendar類的用法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下2023-04-04
nacos配置注冊(cè)中心時(shí)指定命名空間不起作用的問(wèn)題
這篇文章主要介紹了nacos配置注冊(cè)中心時(shí)指定命名空間不起作用的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。2022-01-01
調(diào)用Mybatis?plus中的saveBatch方法報(bào)找不到表的問(wèn)題
在用Mybatis plus開(kāi)發(fā)的項(xiàng)目中,用自帶的API批量保存的方法saveBatch操作時(shí),發(fā)現(xiàn)報(bào)沒(méi)有找到表的錯(cuò)誤,本文就來(lái)詳細(xì)的介紹一下解決方法,感興趣的可以了解一下2024-03-03
Java list與set中contains()方法效率案例詳解
這篇文章主要介紹了Java list與set中contains()方法效率案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
使用java springboot設(shè)計(jì)實(shí)現(xiàn)的圖書(shū)管理系統(tǒng)(建議收藏)
這篇文章主要介紹了使用java springboot設(shè)計(jì)實(shí)現(xiàn)的圖書(shū)管理系統(tǒng),包含了整個(gè)的開(kāi)發(fā)過(guò)程,以及過(guò)程中遇到的問(wèn)題和解決方法,對(duì)大家的學(xué)習(xí)和工作具有借鑒意義,建議收藏一下2021-08-08
java批量導(dǎo)入Excel數(shù)據(jù)超詳細(xì)實(shí)例
這篇文章主要給大家介紹了關(guān)于java批量導(dǎo)入Excel數(shù)據(jù)的相關(guān)資料,EXCEL導(dǎo)入就是文件導(dǎo)入,操作代碼是一樣的,文中給出了詳細(xì)的代碼示例,需要的朋友可以參考下2023-08-08
JAVA進(jìn)階之Spring?Boot自動(dòng)配置示例詳解
Spring Boot自動(dòng)配置是其核心特性之一,極大地簡(jiǎn)化了Spring應(yīng)用的開(kāi)發(fā)過(guò)程,這篇文章主要介紹了JAVA進(jìn)階之Spring?Boot自動(dòng)配置示例詳解的相關(guān)資料,需要的朋友可以參考下2026-01-01

