許多自以為「入門了」的開發者,在這三個基礎問題上仍會翻車。面試必考、實務常見 Bug 來源,徹底搞懂才能寫出正確、高效的 Java 代碼。
String s = "Hello world!";
錯誤認知:「宣告了一個內容為 Hello world 的 String 物件。」
正確認知: 宣告了一個引用變數 s,型別為 String,目前指向常量池中的 "Hello world!" 物件。
String s:引用變數(棧上),佔 4/8 bytes,存放記憶體地址。"Hello world!":String 物件(堆/常量池),內容不可變。String s2 = s;:複製的是引用值(地址),兩個變數指向同一個物件,堆上不會產生新物件。Stack: Heap / String Pool: +-----+ +------------------+ | s | ────────────────► | "Hello world!" | ← 同一物件 +-----+ +------------------+ +-----+ | s2 | ────────────────► +-----+
int a = 10, b = 10;
a == b // true:基本型別比較值
String a = new String("foo");
String b = new String("foo");
a == b // false:兩個 new 產生兩個不同物件,地址不同
// Object 預設實現
public boolean equals(Object o) {
return this == o; // 同樣比較地址!
}
結論: 若類別未覆寫 equals(),呼叫 equals() 效果等同 ==。
String a = new String("foo");
String b = new String("foo");
a.equals(b) // true:比較字元序列內容
class Monster {
private String content;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Monster)) return false;
Monster m = (Monster) o;
return Objects.equals(content, m.content);
}
@Override
public int hashCode() {
return Objects.hash(content);
}
}
鐵律: 覆寫 equals 必須覆寫 hashCode,否則無法用於 HashSet/HashMap/HashTable。
String s = "Hello";
s = s + " world!";
答案:原物件沒變,s 指向新物件。
s 指向常量池 "Hello"。s + " world!" 編譯器優化為 new StringBuilder().append("Hello").append(" world!").toString(),產生新 String 物件 "Hello world!"。s 重新指向新物件,舊 "Hello" 仍在常量池(若無其他引用最終被 GC)。| 場景 | 錯誤寫法 | 正確寫法 | 原因 |
|---|---|---|---|
| 循環拼接 | for() s += x; | StringBuilder sb = new StringBuilder(); for() sb.append(x); | 每次 += 產生新 String + StringBuilder,O(n²) 分配 |
| 常量初始化 | s = new String("Init"); | s = "Init"; | new 總產生新物件;字面量共用常量池 |
| 頻繁修改 | 用 String | 用 StringBuffer/StringBuilder | 可變字元陣列,就地修改,零分配 |
StringBuilder (非同步) / StringBuffer (同步) 互補。| 觀念 | 核心口訣 | 實務鐵律 |
|---|---|---|
| 引用 vs 物件 | 變數存地址,物件在堆上 | 參數傳遞是「值傳遞」(傳引用的值) |
| == vs equals | == 比地址,equals 比內容(若覆寫) | 自定義類用於 Set/Map 必覆寫 equals+hashCode |
| String 不可變 | 改內容 = 換物件 | 拼接用 StringBuilder,常量用字面量 |
String a = "x"; String b = "x"; a == b ? → true (常量池複用)String a = new String("x"); String b = new String("x"); a == b ? → falseString a = "x"; a += "y"; 原 "x" 物件會被修改嗎? → 不會全對才算真正搞懂 Java 基礎三大觀念!