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

深入解析 String、StringBuffer、StringBuilder 源碼與記憶體模型

     編輯:Java 綜合教學

String 核心欄位解析

在 JDK 原始碼中,String 類別主要包含以下關鍵欄位:

  • private final char value[]:用於儲存字符的字符陣列。
  • private final int offset:儲存區中第一個被使用的索引位置。
  • private final int count:字符串實際包含的字符數量。
  • private int hash:緩存字符串的哈希碼,預設為 0。
  • private static final long serialVersionUID:序列化版本號,保持跨版本相容性。

為什麼 final 欄位未直接初始化卻能通過編譯?

final 修飾的欄位並不一定要在宣告時初始化,只要在物件初始化完成(構造器執行結束)前賦值即可。Java 允許在顯式初始化、初始化塊、構造器等任一階段對其賦值,編譯器僅檢查構造器結束前是否已確定賦值。

Java 記憶體區域速覽

Java 記憶體分配涉及以下區域:

  • 暫存器:程式無法直接控制。
  • 棧:儲存基本型別資料與物件引用,物件本身在堆中。
  • 堆:new 出來的物件儲存於此,受 GC 管理。
  • 靜態區:儲存 static 修飾的靜態成員。
  • 常量池:儲存字面常量與符號引用。
  • 非 RAM 儲存:硬碟等永久儲存空間。

棧、堆、方法區三大核心區域

  • 棧:管理非靜態變數生命週期,進出作用域自動入棧/出棧。
  • 堆:物件實體儲存地,引用變數持有首地址,幾乎是 GC 唯一管理區域。
  • 方法區:包含靜態區、非靜態區、常量池;String 常量(如 String s = "123")即存放於常量池。

== 與 equals 的核心差異

  • == 比較的是記憶體地址值。
  • equals 預設也比較地址(依賴 hashCode),但 String 重寫後改為逐字符比較內容值。
public boolean equals(Object anObject) {
    if (this == anObject) return true;
    if (anObject instanceof String) {
        String anotherString = (String) anObject;
        int n = count;
        if (n == anotherString.count) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = offset;
            int j = anotherString.offset;
            while (n-- != 0) {
                if (v1[i++] != v2[j++]) return false;
            }
            return true;
        }
    }
    return false;
}

字符串拼接的記憶體行為

核心法則:

  • 拼接過程中只要有變數參與,結果必為 new 出來的新物件(堆中分配)。
  • 若全為字面常量拼接,編譯期即確定,直接從常量池取值。

經典範例

String s1 = "hello";
String s2 = "world";
String s3 = "helloworld";

System.out.println(s3 == s1 + s2);        // false:s1+s2 產生新物件
System.out.println(s3.equals(s1 + s2));   // true:內容相同
System.out.println(s3 == "hello" + "world"); // true:常量折疊,指向同一常量池對象

final 變數與編譯期優化

String a = "ab";
final String bb = "b";          // 編譯期進入常量池
String b = "a" + bb;            // 編譯期常量折疊 -> "ab"
System.out.println(a == b);     // true

// 若 final 變數由方法返回,則無法編譯期確定
final String bb2 = getBB();     // 運行期賦值
String b2 = "a" + bb2;          // new 物件
System.out.println(a == b2);    // false

方法返回與字符串拼接陷阱

當 final 修飾的變數值來自方法呼叫時,編譯器無法在編譯期完成常量折疊,導致拼接結果為新物件,地址比較返回 false。這類細節將在後續「編譯期確定」專題深入分析。

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