假設遊戲有三種飛行器:Plane、Bird、SpiderMan。它們都要會 takeoff()、fly()、land()。
若用抽象類 Flyer:
public abstract class Flyer {
public abstract void takeoff();
public abstract void fly();
public abstract void land();
}
SpiderMan 已經繼承 SuperMan,Java 單一繼承 限制導致無法同時 extends Flyer。這時介面登場:
public interface Flyer {
void takeoff();
void fly();
void land();
}
public class SpiderMan extends SuperMan implements Flyer {
@Override public void takeoff() { /* 射蛛絲起飛 */ }
@Override public void fly() { /* 蛛絲擺盪 */ }
@Override public void land() { /* 落地滾動 */ }
}
SpiderMan 同時擁有 SuperMan 能力與 Flyer 契約,完美解決單一繼承痛點。
public abstract,不可有方法主體。public static final,只能定義常數。class A implements B, C, D,一個類別可實作多個介面。interface C extends A, B,介面間可多重繼承 (因皆為抽象,無鑽石繼承問題)。public interface Flyer {
void takeoff();
void fly();
void land();
// 預設方法:提供預設實作,實作類可選擇覆寫
default void hover() {
System.out.println("懸停中...");
}
// 靜態方法:屬於介面本身,不可被覆寫,常用工具方法
static String getFlyerType(Class extends Flyer> clazz) {
return clazz.getSimpleName() + " 是飛行器";
}
}
default 讓介面演進不破壞既有實作類。static 替代過去的 Utils 類別,將輔助方法直接放在介面。| 場景 | 選擇 | 理由 |
|---|---|---|
| 定義「是一種」核心身分,需共享狀態/建構子 | 抽象類 | 可有 instance field、建構子、非 public 方法 |
| 定義「具備某能力」、多類別跨層級共用 | 介面 | 可多實作、無狀態、Java 8+ 可提供預設行為 |
| 需要序列化、遠端呼叫 (RMI/WebService) | 介面 | 介面可直接 extends Serializable |
| API 公開給第三方實作 | 介面 | 介面約束更鬆散,利於 SPI 機制 |
abstract。public class Product implements Comparable, Serializable, Cloneable {
private Long id;
private String name;
private BigDecimal price;
@Override public int compareTo(Product o) { return this.id.compareTo(o.id); }
@Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
// Serializable 無需實作方法,標記介面即可
}
default/static 方法讓介面可演進、可攜帶工具邏輯。List<T> list = new ArrayList<>(),降低耦合。