這六個問題看似基礎,實則直擊 Java 物件模型、記憶體語意與語言設計哲學的核心。若你自以為「超越初學者」卻答不上來,請誠實地回歸基礎,重新建立正確心智模型。
String s = "Hello world!"; 到底宣告了什麼?錯誤回答:「宣告了一個內容為 Hello world! 的 String 物件。」
正確回答:宣告了一個名為 s、型別為 String 的參考變數,目前指向字串常量池中的 "Hello world!" 物件。
String s = "Hello world!"; // 參考變數 s → 字串常量池物件
String s2 = s; // 新參考變數 s2 → 同一個物件,並未建立新物件
關鍵區別:變數 ≠ 物件。Java 無變數直接存物件,只有參考指向物件。
== vs equals() —— 比的是「地址」還是「內容」?String a = new String("foo");
String b = new String("foo");
System.out.println(a == b); // false:比較參考地址(兩個 new = 兩個堆上物件)
System.out.println(a.equals(b)); // true:String 覆寫 equals 比較字元內容
==:永遠比較參考值(記憶體地址),基本型別比值、參考型別比地址。equals():Object 預設同 ==,語意由類別設計者決定。String、Integer、集合類別皆覆寫為內容比較。⚠️ 使用HashSet/HashMap/HashTable時,必須確認該類別正確覆寫equals()與hashCode(),否則會出現「明明相等卻存兩份」或「找不到已存入物件」的詭異行為。
String s = "Hello";
s = s + " world!";
發生了什麼:
s 原指向常量池 "Hello"s + " world!" 產生新物件 "Hello world!"(在堆上或常量池,視 JDK 版本優化)s 參考指向新物件,舊 "Hello" 仍在記憶體(若無其他參考則待 GC)結論:String 物件一旦建立內容永不變,所有「修改」操作實則產生新物件。
StringBuilder(非執行緒安全、效能佳)或 StringBuffer(執行緒安全)。s = "value"; 而非 new String("value"),後者每次強制新建物件,浪費記憶體與 CPU。final 到底鎖住了什麼?final StringBuffer a = new StringBuffer("immutable");
a = new StringBuffer("another"); // ❌ 編譯錯誤:參考不可變
final StringBuffer b = new StringBuffer("immutable");
b.append(" broken!"); // ✅ 編譯通過:物件內容可變
鐵律:final 只鎖住參考變數的指向,不鎖住被指向物件的內部狀態。
💡 多執行緒環境下,final 參考指向的可變物件若被多執行緒共享修改,仍會有競態條件。不可變物件才是真正的執行緒安全。
| 變數類型 | 自動初始化 | 預設值 | 備註 |
|---|---|---|---|
| 類別屬性 | ✅ 是 | 0/0.0/false/null/\\u0000 | static 隨類別載入、instance 隨建構子 |
| 區域變數 | ❌ 否 | 無 | 使用前必須明確賦值,否則編譯錯誤 |
| 方法參數 | ✅ 是 | 呼叫端傳入值 | 本質是區域變數,但進入方法時已初始化 |
int x;
if (cond) x = 1; // ❌ 編譯錯誤:cond 為 false 時 x 未初始化
// 必須寫成:
int x = 0; // 或在 else 也賦值
instanceof —— 型別檢查的正確姿勢String s = "test";
boolean b = s instanceof Object; // true:String 繼承 Object
反模式:用 instanceof 分派行為(違反開放封閉原則、模擬多型)。
// ❌ 惡例
if (bill instanceof PhoneBill) calcPhone(bill);
else if (bill instanceof GasBill) calcGas(bill);
正統做法:方法多載或多型。
// ✅ 多載
double calculate(PhoneBill b) { ... }
double calculate(GasBill b) { ... }
// ✅ 多型(Bill 定義抽象 calculate(),子類別實作)
bill.calculate();
掌握這六點,你就真正跨越了「會寫語法」到「懂 Java 運行本質」的鴻溝。