核心規則:覆寫方法的**參數列表必須與父類完全一致**,包括類型、數量、**顯示形式**(變長參數 int... args vs 數組 int[] args)。
class Base {
void fun(int price, int... discounts) { } // 變長參數
}
class Sub extends Base {
@Override
void fun(int price, int[] discounts) { } // 編譯通過,但破壞多態!
}
base.fun(100, 50):編譯器將 50 包裝為 new int[]{50},正常執行子類方法。sub.fun(100, 50):編譯器**不**自動包裝,報錯「找不到 fun(int, int) 方法」。結論:變長參數本質是語法糖,編譯期展開為數組。覆寫時**必須保持變長參數語法**,否則破壞多態調用的一致性。
int count = 0;
for (int i = 0; i < 10; i++) {
count = count++; // 以為 count 會加 10
}
System.out.println(count); // 輸出 0!
count++ 是**後綴自增表達式**,其**值**為自增前的值。JVM 執行步驟:
temp = count (0)count = count + 1 (變為 1)temp (0)count = 0 → 回到初始值修正:直接寫 count++; 或 count = count + 1;。注意:C++ 中 count = count++ 行為未定義,PHP 與 Java 一致。
public class Client8 {
public static void main(String[] args) {
int fee = 200;
saveDefault: save(fee); // 這是一個標籤 + 調用,非語法錯誤!
}
static void saveDefault() { System.out.println("saveDefault"); }
static void save(int fee) { System.out.println("save: " + fee); }
}
// 輸出:save: 200
saveDefault: 是一個**標籤**,可用於 break saveDefault; / continue saveDefault; 跳出多層循環。此處無循環,標籤無實際作用,純屬干擾閱讀。**避免使用標籤**,現代 Java 通過方法提煉、異常、Stream API 更優雅地控制流程。
Math.PI → PI,assertEquals 直接調用。getInstance() 是 NumberFormat 還是本類方法?JUnit Assert.*、Math.PI/E、Collections.emptyList()。import static java.lang.Math.*; ❌import static java.lang.Math.PI;
import static java.lang.Math.abs;
public class Client10 {
public static final String PI = "祖沖之"; // 覆蓋常量
public static int abs(int x) { return 0; } // 覆蓋方法
public static void main(String[] args) {
System.out.println(PI); // "祖沖之" —— 本類常量勝出
System.out.println(abs(-100)); // 0 —— 本類方法勝出
}
}
編譯器「最短路徑」原則:當前類 > 靜態導入 > 父類 > 包導入。本類定義的同名成員**遮蔽**靜態導入成員,導致極難排查的語義錯誤。
最佳實踐:若需修改靜態導入行為,**在原類中重構**,而非在使用方覆蓋。若確需適配,請使用**別名**(Java 無別名機制,可封裝為實例方法調用)。
建議 6-10 圍繞**語法細節陷阱**展開:變長參數覆寫一致性、自增表達式副作用、標籤語句濫用、靜態導入雙刃劍、名稱遮蔽規則。這些看似微小的點,往往是難以復現 Bug 的溫床。將它們內化為編碼肌肉記憶,配合 IDE 檢查、靜態分析,是寫出「不驚艷但不出錯」高質量代碼的關鍵。