介面與抽象類是 Java 抽象機制的雙支柱,語法相似但設計意圖截然不同。本文從語法層面、設計層面、經典案例三個維度徹底釐清,幫你在架構決策中做正確選擇。
| 特性 | 抽象類 | 介面 |
|---|---|---|
| 關鍵字 | abstract class | interface |
| 方法類型 | 抽象 + 具體方法 | JDK 7-:僅抽象 JDK 8+:默認/靜態/私有方法 |
| 成員變量 | 任意修飾符、任意類型 | 隱含 public static final(常量) |
| 構造器 | 可定義(子類調用) | 不可定義 |
| 靜態代碼塊 | 可定義 | JDK 8+ 可定義靜態方法,無靜態塊 |
| 繼承/實現 | 單繼承 (extends) | 多實現 (implements)、介面多繼承 |
| 訪問修飾符 | public/protected/默認/private | 隱含 public(方法/常量) |
Animal、VehicleFlyable、Serializable、Comparable| 關系 | 關鍵字 | 語義 | 例子 |
|---|---|---|---|
| 繼承 | extends | is-a(是一種) | Cat is-a Animal |
| 實現 | implements | like-a / has-a(擁有...能力) | Bird like-a Flyable |
abstract class Door {
abstract void open();
abstract void close();
abstract void alarm(); // 強制所有門都有警報
}
問題:防火門、普通門不需要警報,違反介面隔離原則。
interface Door {
void open();
void close();
void alarm(); // 火災報警器實現此介面卻無 open/close
}
問題:火災報警器不是門,強制實現無意義方法,違反單一職責。
// 核心門行為:抽象類(模板)
abstract class Door {
public abstract void open();
public abstract void close();
}
// 擴展能力:介面(契約)
interface Alarm {
void alarm();
}
// 組合:既是門又有警報
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() { /* 火災警報 */ }
}
default 方法:介面可提供實現,減少抽象類優勢static 方法:工具方法歸屬介面,如 Stream.of()private 方法:默認方法間共享邏輯但本質未變:介面仍無實例狀態、無構造器、多實現語義不變。