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

Java 字串 (String) 深度解析:建立機制、常量池、連接優化與 == vs equals 陷阱

     編輯:J2ME

String 不可變性與常量池

String 建立時寫入實體位址,不可變。任何修改操作都會產生新物件。為避免大量重複字串浪費記憶體,JVM 維護字串常量池(概念類似 ArrayList),相同字面值共用引用。

建立方式差異

寫法建立物件數說明
String s = "abc";1 (池中)查池無則建,回傳池引用
String s = new String("abc");2池中建 "abc" + 堆中建新物件,s 指向堆物件

字串連接 (+) 三種情境

  1. 變數連接:s1 + s2 → JVM 建 StringBuilder、append()、toString() 產生新物件(堆)
  2. 常量連接:"a" + "b" → 編譯期常量折疊,直接產生 "ab" 置於常量池
  3. 混合連接:s + "c" → 視為變數連接,走 StringBuilder 流程

== vs equals() 核心差異

  • ==:比較記憶體位址(引用是否指向同一物件)
  • equals():比較字串內容值

經典測試案例解析

String _abc = "abc";
String _2_abc = "abc";
String _def = "def";
String _abcdef = "abcdef";
String _new_abc = new String("abc");
String _new_abcdef = new String("abcdef");
String _abc_def = _abc + _def;           // 變數連接 → 新物件
String _abc_add_def = "abc" + "def";     // 常量連接 → 池中 "abcdef"
String _new_abc_def = _new_abc + _def;   // 變數連接 → 新物件

// 比較結果
_abc == _2_abc                    // true  (同池引用)
_abc == _new_abc                  // false (池 vs 堆)
_abc == _new_abc.intern()         // true  (intern() 回傳池引用)
_abc_def == _new_abc_def          // false (兩個獨立堆物件)
_abcdef == "abc" + "def"          // true  (常量折疊同池)
_abcdef == _abc_def               // false (池 vs 堆)
_abcdef == _abc_def.intern()      // true  (intern 導向池)
_abcdef == _abc_add_def           // true  (常量連接同池)
_new_abcdef == _abc_add_def       // false (堆 vs 池)
_new_abcdef == _new_abc_def       // false (兩個獨立堆物件)

JVM 連接優化與陷阱

現代 JVM (1.5+) 自動將 s1 + s2 + s3 優化為 new StringBuilder().append(s1).append(s2).append(s3).toString()。

陷阱:迴圈中連接:

String s = "";
for (int i = 0; i < 10; i++) s += i + " "; // 每次迴圈產生新 StringBuilder!

正確寫法:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) sb.append(i).append(' ');
String s = sb.toString();

參數傳遞與不可變性驗證

public static void setString(String s) { s = "321"; }
public static void setString(TestString ts) { ts.string = "321"; }

String str = "123";
setString(str);        // str 仍為 "123" (傳值為引用副本,重新指向不影響原變數)
TestString ts = new TestString();
ts.string = "123";
setString(ts);         // ts.string 變為 "321" (傳物件引用,修改欄位影響原物件)

最佳實務總結

  • 比較內容用 equals(),比較引用用 ==
  • 大量連接務必用 StringBuilder (單執行緒) 或 StringBuffer (多執行緒)
  • 避免不必要的 new String("literal")
  • 需常量池引用時呼叫 intern()
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved