| 版本 | 支持方法類型 | 關鍵字 | 是否有方法體 |
| JDK 1-7 | 抽象方法 | 隱式 public abstract | 否 |
| JDK 8 | 默認方法、靜態方法 | default、static | 是 |
| JDK 9 | 私有方法、私有靜態方法 | private、private static | 是 |
JDK 7 及之前:隱式規則
- 方法自動加上
public abstract,不可寫其他修飾符(private、protected、static、final、synchronized、native、strictfp 均編譯報錯)。
- 變量自動加上
public static final,即常量。
- 無法提供任何實現,實現類必須重寫所有方法(除非是抽象類)。
JDK 8 突破:default & static
默認方法
interface Vehicle {
void start(); // 抽象方法
default void stop() { // 默認方法,有方法體
System.out.println("Vehicle stopped");
}
default void honk() {
System.out.println("Beep beep!");
}
}
- 實現類可選擇性重寫,不重寫則繼承默認實現。
- 解決「接口擴展破壞現有實現」痛點(如
Collection.stream())。
靜態方法
interface MathUtils {
static int max(int a, int b) { return a > b ? a : b; }
static double PI = 3.14159; // 實際是常量
}
// 調用:MathUtils.max(1,2) —— 不能通過實現類實例調用
- 屬於接口本身,不可被繼承、不可被重寫(可隱藏)。
- 用於工具方法聚合,替代單獨的 Utils 類。
鑽石繼承衝突與解決規則
interface A { default void foo() { System.out.println("A"); } }
interface B { default void foo() { System.out.println("B"); } }
interface C extends A, B { } // 編譯錯誤:繼承了衝突的默認方法
// 解決:C 必須顯式重寫並指定調用哪個
interface C extends A, B {
default void foo() { A.super.foo(); } // 顯式選擇 A 的實現
}
規則:
- 類優先:實現類自己的方法 > 接口默認方法。
- 具體優先:若繼承鏈中有非默認方法(抽象或類實現),則該方法勝出。
- 否則必須顯式重寫並用
Interface.super.method() 選擇。
JDK 9 補充:private 方法
interface Complex {
private void helper() { ... } // 實例私有方法
private static void staticHelper() { ... } // 靜態私有方法
default void publicApi() { helper(); } // 默認方法內部復用
static void staticApi() { staticHelper(); }
}
- 將默認/靜態方法中的共享邏輯提取為私有方法,避免暴露細節。
- 私有方法不可被繼承、不可被實現類調用。
常見誤區與面試陷阱
| 誤區 | 真相 |
| 接口方法默認是 protected | 默認 public,不可降低可見性 |
| default 方法可以被 override 為 abstract | 可以,子接口可重新聲明為 abstract,強制實現類實現 |
| static 方法可以被繼承 | 不可繼承,只能通過 接口名.方法名() 調用 |
| 接口中可以定義實例字段 | 只能定義 public static final 常量 |
| 函數式接口只能有一個 default 方法 | 函數式接口只能有一個抽象方法,default 方法不限數量 |
最佳實踐建議
- 接口定義契約,類實現細節:優先用抽象方法表達核心契約。
- 默認方法慎用:僅用於「向後兼容擴展」或「提供通用輔助實現」,避免業務邏輯下沉到接口。
- 靜態方法聚合工具:如
Stream.of()、Comparator.naturalOrder(),替代 XxxUtils 類。
- 文檔化契約:用 Javadoc @apiNote @implSpec 說明默認方法行為與重寫約束。
- 避免鑽石繼承:接口繼承樹保持扁平,必要時用組合代替多重繼承。
文中提到的 Iterator 示例補充
Collection c = new ArrayList<>();
c.add("123"); c.add("456"); c.add("789");
Iterator it = c.iterator(); // 獲取迭代器實例
while (it.hasNext()) {
System.out.println(it.next()); // 依次輸出 123 456 789
}
此處 iterator() 是 Collection 接口的抽象方法,ArrayList 提供具體實現,返回內部類 Itr 實例。體現「面向接口編程」:客戶代碼只依賴 Iterator 契約,不依賴具體集合實現。
- 上一篇文章: 深入淺出《Unix環境高級編程》筆記(三):程序與進程、PID 文件鎖、fork/wait 進程控制實戰
- 下一篇文章: Eclipse 啟動報錯「Failed to load the JNI shared library jvm.dll」根因與 30 秒修復
Copyright ©
程式碼之家 All Rights Reserved