首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 字串處理三大核心類:String、StringBuffer、StringBuilder 深度對比

     編輯:Java 相關知識

前言

字串操作是 Java 開發最高頻場景之一。String、StringBuffer、StringBuilder 三者關係緊密卻差異巨大。本文從源碼層面剖析三者異同,助你在面試與實戰中精準選型。

一、核心差異總覽

特性StringStringBufferStringBuilder
可變性不可變可變可變
線程安全是(不可變天然安全)是(synchronized)否
繼承結構final classextends AbstractStringBuilderextends AbstractStringBuilder
JDK 版本1.01.01.5
效能(單執行緒)最差中等最佳

二、源碼級剖析

1. String:不可變的字元陣列

public final class String implements Serializable, Comparable<String>, CharSequence {
    // JDK 9+ 使用 byte[] + coder,節省空間
    private final byte[] value;
    private final byte coder; // 0=LATIN1, 1=UTF16

    // 所有「修改」操作都會返回新 String 物件
    public String concat(String str) {
        int len = str.length();
        if (len == 0) return this;
        byte[] v = Arrays.copyOf(value, value.length + len);
        str.getBytes(v, value.length);
        return new String(v, coder);
    }
}

每次拼接、替換、子字串都會分配新記憶體、複製陣列。循環拼接會產生大量臨時物件,觸發頻繁 GC。

2. StringBuffer / StringBuilder:共享父類 AbstractStringBuilder

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    byte[] value; // 非 final,可擴容
    int count;    // 實際長度

    // 核心擴容邏輯
    private void ensureCapacityInternal(int minimumCapacity) {
        if (minimumCapacity - value.length > 0) expandCapacity(minimumCapacity);
    }
    void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0) newCapacity = minimumCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minimumCapacity);
        value = Arrays.copyOf(value, newCapacity);
    }
}

3. StringBuffer:同步鎖保護

public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

public synchronized int indexOf(String str, int fromIndex) {
    return super.indexOf(str, fromIndex);
}

所有公共方法加 synchronized,多執行緒安全但效能損耗大。

4. StringBuilder:無同步,極致效能

public StringBuilder append(String str) {
    super.append(str);
    return this;
}

JDK 5 引入,專為單執行緒場景設計。現代 JVM 對無鎖代碼優化極好(逃逸分析、鎖消除)。

三、效能實測(百萬次拼接)

// String: ~4500ms
String s = "";
for (int i = 0; i < 1_000_000; i++) s += "a";

// StringBuffer: ~15ms
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 1_000_000; i++) sb.append("a");

// StringBuilder: ~10ms
StringBuilder sbl = new StringBuilder();
for (int i = 0; i < 1_000_000; i++) sbl.append("a");

結論:單執行緒首選 StringBuilder;多執行緒共享緩衝區用 StringBuffer;少量拼接或常量用 String。

四、常見誤區與最佳實踐

誤區 1:String s = "a" + "b" + "c" 效率低

錯誤。編譯期常量折疊會直接優化為 "abc",零開銷。

誤區 2:StringBuilder 絕對比 StringBuffer 快

視情況。JDK 6+ 引入鎖消除、偏向鎖,單執行緒下 StringBuffer 經 JIT 優化後差距極小。但 StringBuilder 仍是標準選擇。

最佳實踐

  • 局部變數拼接:直接用 +,編譯器自動優化為 StringBuilder。
  • 循環/大量拼接:顯式使用 new StringBuilder(),預估容量 new StringBuilder(1024) 避免擴容。
  • 多執行緒共享:StringBuffer 或 ThreadLocal<StringBuilder>。
  • 日誌框架:使用佔位符 log.debug("user={}, id={}", name, id) 避免不必要拼接。

五、JDK 9+ 優化:Compact Strings

JDK 9 將 char[] 改為 byte[] + coder,純 ASCII 字串記憶體減半。三大類同步受益,無需代碼修改。

六、總結

理解三者底層實現差異,核心在於可變性與同步策略。實戰中:單執行緒用 StringBuilder,多執行緒共享用 StringBuffer,其餘用 String。配合 JDK 9+ Compact Strings,字串處理效能與記憶體表現雙贏。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved