接口是 Java 面向對象設計的契約基石。從 JDK 1.0 的「純抽象契約」演進至 JDK 8+ 的「默認方法、靜態方法、私有方法」,接口已成為行為抽象、多實現切換、框架 SPI 擴展的核心載體。本文從概念本質、語法演進、設計模式應用、與抽象類對比四個維度,徹底講透接口精髓。
// SATA 硬盤接口:定義行為契約
public interface SataHdd {
int CONNECT_LINES = 4; // 默認 public static final
void writeData(String data);
String readData();
}
// 希捷、三星、西數各自實現接口
class SeagateHdd implements SataHdd { ... }
class SamsungHdd implements SataHdd { ... }
// 客戶端只依賴接口,不依賴具體實現
SataHdd hdd = new SeagateHdd(); // 可隨時換成 SamsungHdd
hdd.writeData("重要數據");
接口實現了依賴倒置:高層模塊依賴抽象,低層模塊實現抽象。
| 版本 | 新增特性 | 影響 |
|---|---|---|
| JDK 1.0 | 常量、抽象方法 | 純契約,單繼承限制下的多實現補位 |
| JDK 8 | 默認方法、靜態方法 | 接口可攜帶實現,解決「擴展接口破壞舊實現」痛點 |
| JDK 9 | 私有方法、私有靜態方法 | 默認方法間可復用邏輯,封裝細節 |
| JDK 10+ | 無重大語法變更 | — |
public interface Loggable {
// 默認實現:所有實現類自動擁有 log() 能力
default void log(String msg) {
System.out.println("[" + now() + "] " + msg);
}
// 靜態工具方法:屬於接口,不可覆寫
static String now() { return LocalTime.now().toString(); }
// 私有方法:JDK 9+,供默認方法內部復用
private void internalLog(String level, String msg) { ... }
}
鑽石問題解決:類實現多個接口有同名默認方法 → 必須顯式覆寫並選擇調用哪個(InterfaceA.super.defaultMethod())。
| 維度 | 接口 | 抽象類 |
|---|---|---|
| 方法實現 | JDK 8 前全抽象;JDK 8+ 可有默認/靜態/私有 | 可有任意實例方法實現 |
| 字段 | 只能 public static final 常量 | 可有實例字段、構造器、初始化塊 |
| 繼承關係 | 多實現:implements A, B, C | 單繼承:extends Base |
| 構造器 | 無 | 有(供子類調用) |
| 訪問修飾 | 默認 public,JDK 9+ 可 private | 任意 |
| 設計意圖 | 定義能力契約(Can-do),如 Serializable、Comparable | 定義實體骨架(Is-a),共享代碼、強制規範 |
Animal → Mammal → Cat) → 抽象類Cloneable、Runnable、Comparator) → 接口interface Strategy { execute(); } — 運行期熱插拔算法。interface Factory { Product create(); } — 解耦創建邏輯。interface Listener { onEvent(Event e); } — 發布訂閱標準契約。java.util.ServiceLoader 掃描 META-INF/services/接口全限定名 — JDBC 驅動、日誌門面、緩存提供者標準化擴展機制。@FunctionalInterface) — Lambda 表達式、方法引用、Stream API 基石。錯誤:interface Machine { print(); scan(); fax(); email(); } — 強迫只會打印的類實現掃描/傳真。
正確:拆分為 Printer、Scanner、Fax、Emailer,類按需組合實現。
int x = 1; 實為 public static final int x = 1;,不可修改。Serializable、Cloneable)僅供框架反射檢測,業務代碼勿濫造。接口是 Java 靈活性的源頭。善用接口定義契約、隔離變化、支援多實現、實現 SPI 擴展,是從「寫代碼」進階到「做架構」的關鍵能力。