| 維度 | 抽象類 | 介面 |
|---|---|---|
| 關鍵字 | abstract class | interface |
| 方法 | 可有抽象方法,也可有具體實現、靜態方法、私有方法 | JDK8 前:全抽象;JDK8+:可有 default、static、private 方法 |
| 欄位 | 任意修飾符、任意類型 | 隱式 public static final(常量) |
| 構造器 | 可有(供子類鏈式調用) | 無 |
| 繼承/實現 | extends 單繼承 | implements 多實現 |
| 本質 | is-a:對「一類事物」的抽象(屬性+行為) | has-a:對「一組行為」的抽象(契約) |
super(...) 調用。static 方法。implements 多個介面。父類定義通用骨架/默認實現,子類繼承並覆寫差異點。修改父類默認實現 → 所有子類自動獲得(除非覆寫)。如 HttpServlet、AbstractList。
定義行為契約,實現類必須實現所有抽象方法。介面新增方法 → 所有實現類強制編譯報錯,需逐一修改。如 Comparable、Runnable、JDBC Driver。
錯誤設計 1:全塞進抽象類
abstract class Door { abstract void open(); abstract void close(); abstract void alarm(); }
→ 所有門都有警報,但防火門可能不需要。
錯誤設計 2:全塞進介面
interface Door { void open(); void close(); void alarm(); }
→ 火災報警器實現 Door 卻沒有 open/close,違反 ISP。
正確設計:職責分離
// 核心屬性:門的本質行為
abstract class Door {
public abstract void open();
public abstract void close();
}
// 擴展行為:警報能力
interface Alarm {
void alarm();
}
// 組合:具有警報功能的門
class AlarmDoor extends Door implements Alarm {
public void open() { System.out.println("門打開"); }
public void close() { System.out.println("門關閉"); }
public void alarm() { System.out.println("警報響起!"); }
}
// 純警報器:無門行為
class FireAlarm implements Alarm {
public void alarm() { System.out.println("火災報警!"); }
}
原則:抽象類建模「是什麼」,介面建模「能做什麼」。
abstract class AbstractParser {
// 模板方法:final 禁止覆寫,鎖定流程
public final void parse() {
readHeader();
parseBody();
readFooter();
}
// 子類必須實現
protected abstract void parseBody();
// 可選覆寫(鉤子方法)
protected void readHeader() { System.out.println("讀取通用頭"); }
protected void readFooter() { System.out.println("讀取通用尾"); }
}
class JsonParser extends AbstractParser {
protected void parseBody() { System.out.println("解析 JSON 體"); }
// 可選覆寫 header/footer
}
protected 允許子類訪問、覆寫,但對外部不可見,完美支援模板方法模式。
final class:不可被繼承(如 String、Integer)。final method:不可被覆寫(鎖定關鍵邏輯)。final variable:引用不可變(對象內部狀態仍可變)。AbstractList implements List)。default 方法,輕量共享邏輯可直接寫在介面,減少抽象類層級。| 誤區 | 正確理解 |
|---|---|
| 「介面不能有實現」 | JDK8+ 可有 default/static/private 方法 |
| 「抽象類必須有抽象方法」 | 可無抽象方法,純為防止實例化、提供共享代碼 |
| 「用介面代替抽象類總是更好」 | 需共享實例狀態/構造器時,抽象類不可替代 |
| 「多實現用抽象類」 | Java 單繼承,多實現只能靠介面 |
深入理解抽象類與介面的語義邊界,而非語法細節,才能在架構設計中做出正確選擇,避免過度設計或僵化結構。