| 比較對象 | == 比較 | equals() 比較 |
|---|---|---|
| 基本型別 | 比較值 | N/A(基本型別無方法) |
| 引用型別 | 比較記憶體地址(是否同一物件) | 預設比較地址;String、Integer、Date 等類別重寫後比較「內容」 |
JVM 為節省記憶體,維護一個字符串常量池(String Pool)。直接使用雙引號字面量(String s = "abc")建立字符串時:
因此:
String s1 = "Monday";
String s2 = "Monday";
System.out.println(s1 == s2); // true,同一池物件
使用 new 關鍵字時,繞過常量池,直接在堆中建立新物件:
String s1 = "Monday";
String s2 = new String("Monday");
System.out.println(s1 == s2); // false,不同物件
System.out.println(s1.equals(s2)); // true,內容相同
String.intern() 是 Native 方法,執行邏輯:
String s1 = "Monday";
String s2 = new String("Monday");
s2 = s2.intern(); // 手動入池
System.out.println(s1 == s2); // true,現在指向同一池物件
String s1 = "Monday"; String s2 = new String("Monday");
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ String Pool │ │ Heap │ │ String Pool │
│ "Monday" ◄──┼───── s1 │ "Monday" ◄──┼──── s2 │
└──────────────┘ └──────────────┘ └──────────────┘
▲ ▲
│ │
s1 == s2 為 true s1 == s2 為 false
equals(),除非你確定雙方皆來自常量池(如枚舉、單例模式)。new String(),直接用字面量享受常量池複用優勢。intern(),但注意:JDK 6 常量池在 PermGen(易 OOM),JDK 7+ 移至 Heap,使用相對安全。hashCode(),否則在 HashMap/HashSet 中會失效。String s1 = "a" + "b"; // 編譯期常量折疊 → "ab" 入池
String s2 = "ab"; // 字面量 → 池中同一物件
String s3 = new String("a") + new String("b"); // 運行期 new → 堆中新物件
String s4 = s3.intern(); // 手動入池
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s1 == s4); // true
== 比較引用地址,equals() 比較邏輯內容(視類別實現而定)。字符串常量池與 intern() 是 JVM 優化字符串存儲的關鍵機制,理解其運作原理能避免 90% 的字符串比較 Bug,也是高頻面試必考點。