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

JVM 字節碼分析:String 比較與常量池機制深度解析

     編輯:Java 綜合教學

JVM 字節碼分析:String 比較與常量池機制深度解析

透過 javap -c 反編譯字節碼,深入理解 String s1 = "a"; s1 + "b" 與 "a" + "b" 在記憶體與常量池的不同行為。

測試程式碼

public class StringDemo {
    public static void aa() {
        String s1 = "a";           // 常量池
        String s2 = "b";           // 常量池
        String s12 = "ab";         // 常量池
        String s3 = s1 + s2;       // 執行期 new StringBuilder().append().toString() → 堆
        System.out.println(s3 == s12); // false
    }
    public static void bb() {
        String s1 = "a" + "b";     // 編譯期常量折疊 → "ab" 進常量池
        String s2 = "ab";          // 常量池同一引用
        System.out.println(s1 == s2); // true
    }
}

字節碼解析:aa() 方法

 0: ldc #3        // "a" → 常量池
 2: astore_0
 3: ldc #4        // "b" → 常量池
 5: astore_1
 6: ldc #5        // "ab" → 常量池
 8: astore_2
 9: new #6        // new StringBuilder
12: dup
13: invokespecial #7 // StringBuilder.
16: aload_0
17: invokevirtual #8 // append("a")
20: aload_1
21: invokevirtual #8 // append("b")
24: invokevirtual #9 // toString() → new String(heap)
27: astore_3      // s3 指向堆記憶體
28: aload_3
29: aload_2
30: if_acmpne 37  // 比較引用地址:堆 vs 常量池 → 不同
33: iconst_1
34: goto 38
37: iconst_0
38: invokestatic #10 // Boolean.valueOf
41: invokestatic #11 // print(false)
44: return

關鍵指令說明

  • ldc:將常量池字面值推入棧頂
  • new / invokespecial:建立 StringBuilder 實例
  • invokevirtual:呼叫實例方法 append、toString
  • toString 內部 new String(value, 0, count) → 堆記憶體新物件
  • if_acmpne:比較兩引用地址是否相同

字節碼解析:bb() 方法

 0: ldc #5        // "ab" → 常量池(編譯期常量折疊)
 2: astore_0
 3: ldc #5        // 同一常量池項目
 5: astore_1
 6: aload_0
 7: aload_1
 8: if_acmpne 15  // 引用相同 → true
11: iconst_1
12: goto 16
15: iconst_0
16: invokestatic #10 // Boolean.valueOf(true)
19: invokestatic #11 // print(true)
22: return

編譯期優化

"a" + "b" 為編譯期常量表達式,javac 直接折疊為 "ab" 存入常量池,故 s1、s2 指向同一引用。

補充知識點

  • iconst_0/1:將 int 0/1 推入棧頂,boolean 在 JVM 中佔 4 bytes(同 int)
  • Boolean.valueOf():基本型別自動裝箱為包裝類
  • 字串連接 + 非常量表達式時,編譯器生成 StringBuilder 代碼(JDK 1.5+)

最佳實務

  • 比較字串內容請用 equals()
  • 大量字串拼接使用 StringBuilder 或 StringJoiner
  • 理解常量池與堆的區別,避免 == 誤判
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved