抽象類別與介面都是定義「契約」的機制,但意圖、語法限制、設計哲學截然不同。本文從語法層面、設計層面、經典範例三個維度深度剖析,助你做出正確架構決策。
| 特性 | 抽象類別 (abstract class) | 介面 (interface) |
|---|---|---|
| 關鍵字 | abstract class | interface |
| 方法實作 | 可有具體方法、抽象方法 | Java 7 前僅抽象方法;Java 8+ 可有 default/static/private 方法 |
| 成員變數 | 任意型別、任意修飾詞 | 隱含 public static final(常數) |
| 建構子 | 可有(供子類別呼叫) | 不可有 |
| 繼承/實作 | 單繼承(extends 一個) | 多實作(implements 多個) |
| 存取修飾詞 | 抽象方法預設 public/protected | 方法隱含 public |
| 靜態區塊/方法 | 可有 | Java 8 前不可有;Java 8+ 可有 static 方法 |
| 維度 | 抽象類別 | 介面 |
|---|---|---|
| 抽象對象 | 「是一種」關係:對整個類別整體抽象(屬性+行為) | 「有能力」關係:對行為單一面向抽象 |
| 設計模式 | 模板方法模式:定義演算法骨架,延遲細節到子類別 | 策略模式:定義行為契約,支援多種實作熱插拔 |
| 演進影響 | 新增具體方法不影響子類別 | 新增抽象方法破壞所有實作類(Java 8 default 方法緩解) |
| 典型用途 | 領域模型基類、共享程式碼、狀態管理 | 能力標記、API 契約、跨層級解耦 |
// 錯誤設計:將警報行為塞進 Door 抽象類別
abstract class Door {
public abstract void open();
public abstract void close();
public abstract void alarm(); // 強迫所有門都有警報
}
// 正確設計:行為分離
interface Alarm {
void alarm();
}
abstract class Door {
public abstract void open();
public abstract void close();
}
// 需要警報功能的門,組合繼承+實作
class AlarmDoor extends Door implements Alarm {
@Override public void open() { /*...*/ }
@Override public void close() { /*...*/ }
@Override public void alarm() { /*...*/ }
}
// 純警報器(非門),只實作介面
class FireAlarm implements Alarm {
@Override public void alarm() { /*...*/ }
}
interface Logger {
void log(String msg);
default void info(String msg) { log("[INFO] " + msg); } // 提供預設實作
default void error(String msg) { log("[ERROR] " + msg); }
}
介面現在可提供預設實作,減少抽象類別的必要性,但介面仍無法擁有實例狀態(non-static fields),這是本質區別。
AbstractXXX)實作介面,子類別繼承基類。Serializable, Cloneable, Comparable 風格)。