| 維度 | 抽象類別 | 介面 |
| 關鍵字 | abstract class | interface |
| 繼承/實作 | extends (單一) | implements (多重) |
| 成員欄位 | 任意 (實例/靜態、final/非 final) | 隱含 public static final (常數) |
| 方法 | 抽象 + 具體 (預設非 static) | 抽象 + default + static + private (Java 8+) |
| 建構子 | 有 (供子類建構子呼叫) | 無 |
| 存取修飾符 | 任意 | 隱含 public (Java 9+ 允許 private 方法) |
| 核心關係 | is-a (泛化/特化) | can-do / has-capability (契約/行為) |
語法層面比較
// 抽象類版本
abstract class Animal {
String name; // 共享狀態
abstract void makeSound(); // 強制子類實作
void breathe() { System.out.println("Breathing..."); } // 共享邏輯
}
// 介面版本
interface Animal {
void makeSound(); // 契約
default void breathe() { System.out.println("Breathing..."); } // Java 8+ 預設實作
static boolean isAlive(Animal a) { return a != null; } // 工具方法
}
設計哲學層面:三大核心差異
1. 抽象層次不同
- 抽象類別:對**整個實體**進行抽象 (屬性 + 行為)。提取子類共同的**本質特徵**。
- 介面:對**單一行為/能力**進行抽象。定義**「能做什麼」**,不關心「是什麼」。
2. 跨域範圍不同
- 抽象類別:適用於**高度相關**的類別層次結構 (如
Animal → Dog, Cat、Vehicle → Car, Truck),必須滿足 is-a 關係 (里氏替換原則)。
- 介面:可跨越**完全無關**的類別 (如
Bird implements Flyable, Airplane implements Flyable, Superman implements Flyable)。無需共同父類。
3. 設計方向不同
- 抽象類別:**自底向上** (重構而來)。先有具體類別 → 發現共同點 → 提取抽象父類。
例:已有 Dog、Cat → 提取 Animal。
- 介面:**自頂向下** (契約先行)。先定義能力規範 → 後續各類別獨立實作。
例:定義 Flyable → 未來任何會飛的類別皆可實作。
經典案例:門與警報器
// 需求:門有開/關;現需增加警報功能
// 方案 1:單一介面/抽象類混雜 (違反 ISP 介面隔離原則)
interface Door { void open(); void close(); void alarm(); } // 門職責過重
// 方案 2:拆分為兩個介面 (純介面)
interface Door { void open(); void close(); }
interface Alarm { void alarm(); }
class AlarmDoor implements Door, Alarm { ... } // 多實作
// 方案 3:抽象類 + 介面 (語義最精確) — 推薦
abstract class Door { abstract void open(); abstract void close(); }
interface Alarm { void alarm(); }
class AlarmDoor extends Door implements Alarm { ... }
// 語義:AlarmDoor **本質是門** (is-a Door) + **具備警報能力** (has-capability Alarm)
選擇決策樹
- 是否需要**共享狀態/非最終欄位/建構子邏輯**?
→ 是 → 抽象類別 (或具體類別)。
- 是否需要**多重實作/跨無關類別賦予能力**?
→ 是 → 介面。
- 是否為**高度相關的類別家族** 提取共同本質?
→ 是 → 抽象類別** 定義骨架,介面定義擴展能力。
- 是否為 **API 公開契約** (供第三方實作)?
→ 是 → 介面** (二進制相容性更好,新增 default 方法不破壞實作類)。
- 是否需要**提供預設實作供選擇性覆寫**?
→ 介面 default 方法 (Java 8+) 或 抽象類別具體方法均可。介面更靈活 (可多實作)。
現代 Java 最佳實踐 (Java 8+)
- 介面優先:定義核心契約,用
default 提供共享邏輯,static 提供工具方法。
- 抽象類作為骨架:當介面無法表達共享狀態/建構子邏輯時,提供
abstract class BaseImpl implements Interface 作為便利基類 (如 AbstractList, AbstractMap)。
- 組合優於繼承:行為變化用策略模式 (介面注入),而非建立深層繼承樹。
- 封閉介面 (Java 17+
sealed interface):限制實作類別範圍,兼具介面靈活性與封閉性。
總結對照表
| 場景 | 推薦 | 理由 |
| 模板方法模式 (骨架算法 + 變化步驟) | 抽象類別 | 共享流程控制、狀態、建構子 |
| 可插拔擴展點 (插件、驅動、策略) | 介面 | 多實作、解耦、跨域 |
| 領域模型核心實體 (Entity) | 抽象類別/具體類別 | 豐富領域行為、狀態封裝 |
| API 公開契約 (SPI) | 介面 | 二進制相容、多廠商實作 |
| 工具方法集合 | 介面 static 方法 | 命名空間分組、無實例化 |
| 測試雙件 | 介面 | 易 Mock、易替換 |
結語
抽象類別表達「是什麼」(is-a),介面表達「能做什麼」(can-do)。 現代 Java 開發中,**介面為主、抽象類為輔、組合為本**。理解兩者設計意圖差異,比記憶語法規則更重要。
- 上一篇文章: Java 內部類完整教學:四大類型、.this/.new 語法、編譯產物、最佳實踐
- 下一篇文章: Java 條件編譯完全指南:原理、實現與最佳實踐
Copyright ©
程式碼之家 All Rights Reserved