抽象類是 Java 實現多態與程式碼復用的核心機制之一。本文從語法規範、設計意圖、模板方法模式、介面對比、實戰陷阱五個維度系統講解抽象類的核心知識體系。
| 規則 | 說明 | 代碼示例 |
|---|---|---|
| 關鍵字 | abstract 修飾類或方法 | abstract class Animal {} |
| 抽象方法 | 無方法體,僅聲明簽名,子類必須實現 (除非子類也為抽象) | abstract void run(); |
| 非抽象方法 | 抽象類可包含具體方法、靜態方法、私有方法、建構子 | public void breathe() {} |
| 不可實例化 | new Animal() 編譯錯誤,只能作為父類被繼承 | // Animal a = new Animal(); ✗ |
| 建構子用途 | 供子類 super() 呼叫初始化父類狀態,不可被外部直接調用 | protected Animal(String name) {} |
| 無抽象方法也可宣告 abstract | 強制被繼承,防止直接實例化 (如 HttpServlet) | abstract class BaseController {} |
| final 與 abstract 互斥 | final 類不可繼承,final 方法不可覆寫 | // abstract final void m(); ✗ |
抽象類定義演算法骨架,將特定步驟延遲到子類實現,符合「好萊塢原則」——「別調用我們,我們會調用你」。
/**
* 資料導入模板:讀取 → 驗證 → 轉換 → 持久化 → 通知
*/
public abstract class DataImporterTemplate<T> {
// 最終方法:鎖定演算法流程,禁止子類覆寫
public final void importData(InputStream input) {
List<T> rawData = readData(input); // 1. 讀取 (抽象)
List<ValidatedRecord<T>> validated = validate(rawData); // 2. 驗證 (模板提供預設)
List<Entity> entities = transform(validated); // 3. 轉換 (抽象)
persist(entities); // 4. 持久化 (模板提供預設)
notifyComplete(entities.size()); // 5. 通知 (鉤子方法)
}
// 抽象方法:子類必須實現
protected abstract List<T> readData(InputStream input);
protected abstract List<Entity> transform(List<ValidatedRecord<T>> validated);
// 具體方法:提供預設實現,子類可選擇性覆寫
protected List<ValidatedRecord<T>> validate(List<T> rawData) {
return rawData.stream()
.map(this::validateSingle)
.collect(Collectors.toList());
}
protected void persist(List<Entity> entities) {
entityRepository.saveAll(entities);
}
// 鉤子方法:預設空實現,子類按需擴充
protected void notifyComplete(int count) {
log.info("導入完成,共 {} 筆", count);
}
// 私有輔助方法:封裝內部細節
private ValidatedRecord<T> validateSingle(T item) { ... }
}
public class ExcelUserImporter extends DataImporterTemplate<Row> {
@Override
protected List<Row> readData(InputStream input) {
// POI 解析 Excel 行
}
@Override
protected List<Entity> transform(List<ValidatedRecord<Row>> validated) {
// Row → UserEntity 轉換邏輯
}
@Override
protected void notifyComplete(int count) {
super.notifyComplete(count);
emailService.sendAdminReport(count);
}
}
| 維度 | 抽象類 | 介面 (Java 8+) |
|---|---|---|
| 繼承關係 | 單繼承 (extends) | 多實現 (implements) |
| 狀態 (欄位) | 支援實例欄位、建構子 | 僅 static final 常量 (Java 8 前) |
| 方法實現 | 抽象 + 具體 + 靜態 + 私有 | 抽象 + default + static + private |
| 適用場景 | 「is-a」強關聯、共享狀態/邏輯、模板方法 | 「can-do」能力定義、多型解耦、SPI 擴充點 |
| 演進兼容性 | 新增具體方法不破壞子類 | 新增 default 方法不破壞實現類 |
決策口訣:
需要共享代碼/狀態 → 抽象類
定義能力契約、多實現、插件化 → 介面
兩者兼備 → 抽象類實現介面 (如 AbstractList implements List)
抽象類是「不完整的類」,以「抽象」描述契約,以「具體」復用邏輯。掌握模板方法模式、合理劃分抽象與具體邊界、警惕繼承濫用,能讓你設計出既靈活又穩健的類別體系。現代 Java 開發中,介面配合 default 方法已承擔部分抽象類職責,但抽象類在狀態管理、強約束繼承鏈、建構子鏈初始化等場景仍不可替代。