Java interface abstract default method

[Java] 介面與抽象類別

前面 OOP 入門講過 class 與繼承,這篇進到更上層的型別抽象——abstract classinterface。Java 是單一繼承語言,要做「能力組合」靠的是介面:一個類別能 implements 多個介面,也是 Java 對 mixin / trait / Protocol 這類概念的回答。

抽象類別 abstract class

不能被 new 出來,只能被繼承。可以有實作的方法、也可以有抽象方法(abstract,沒方法體)。

abstract class Animal {
    protected String name;

    public Animal(String name) {        // 可有建構子
        this.name = name;
    }

    public void sleep() {                // 一般方法
        System.out.println(name + " is sleeping");
    }

    public abstract void speak();        // 抽象方法,子類必須實作
}

class Dog extends Animal {
    public Dog(String name) { super(name); }

    @Override
    public void speak() {
        System.out.println(name + ": woof");
    }
}

// new Animal("a");   // ❌ 編譯錯:不能實例化抽象類
new Dog("Rex").speak();

介面 interface

定義「行為契約」,類別用 implements 實作。介面可被多重實作(補了 Java 單一繼承的限制)。

interface Drawable {
    void draw();          // public abstract(預設可省)
}

interface Resizable {
    void resize(double factor);
}

class Circle implements Drawable, Resizable {
    @Override public void draw() { System.out.println(""); }
    @Override public void resize(double f) { /* ... */ }
}

default method(Java 8+)

介面可以有「預設實作」,類別不寫也能用:

interface Greeter {
    String name();

    default String greet() {
        return "Hi, " + name();
    }
}

class User implements Greeter {
    @Override public String name() { return "Jeremy"; }
}

new User().greet();    // "Hi, Jeremy"

主要用途:替既有介面加新方法又不破壞所有 implementor。

如果兩個介面有同名的 default method,一個 class 同時 implement 兩者會編譯錯誤(diamond problem)。解法是自己覆寫該方法,用 Interface.super.method() 指明要哪一個,例如 Walker.super.move()

static method 與 private method(Java 9+)

interface MathUtil {
    static int square(int x) { return x * x; }    // 直接 MathUtil.square(3)

    default int doubleSquare(int x) {
        return helper(x) * 2;
    }

    private int helper(int x) {                    // 只給介面內部用
        return x * x;
    }
}

常數欄位

介面內的欄位自動是 public static final

interface Limits {
    int MAX_RETRY = 3;     // 等同 public static final int MAX_RETRY = 3
}

abstract class vs interface 怎麼選

比較項abstract classinterface
多重支援單一繼承多重實作
欄位可有狀態(instance field)只能 static final 常數
建構子
方法可見性任意只能 public(含 default
適合場景共用狀態 + 共用實作純行為契約、跨類型共用能力

實務取捨:能用 interface 解的都優先 interface,需要共用狀態或建構邏輯才動 abstract class。

functional interface

只有一個抽象方法的介面,可被 lambda 賦值:

@FunctionalInterface
interface Calc {
    int apply(int a, int b);
}

Calc add = (a, b) -> a + b;
add.apply(2, 3);      // 5

@FunctionalInterface 不是必須,但加上後編譯器會檢查「真的只有一個抽象方法」。

JDK 已內建一票 functional interface(FunctionPredicateConsumerSupplier 等),下下篇 Lambda/Stream 會專門講。

sealed class / sealed interface(Java 17+)

明確列出「誰可以繼承 / 實作」,編譯器能做窮舉檢查:

sealed interface Shape permits Circle, Square, Triangle {}

final class Circle implements Shape {}
final class Square implements Shape {}
non-sealed class Triangle implements Shape {}

子型別必須是 finalsealednon-sealed 三選一。配合 switch pattern matching 寫窮舉處理特別清楚。

record 與 interface

record 是 Java 16+ 的「不可變資料類別」,可以實作介面:

interface HasArea {
    double area();
}

record Rect(double w, double h) implements HasArea {
    @Override public double area() { return w * h; }
}

record 自動產生建構子、equalshashCodetoString 與欄位 accessor。當作 DTO / value object 很順手。

@Override 標註

不是必須,但強烈建議:拼錯方法名或簽章不對時,編譯器會擋下來。

class Dog extends Animal {
    @Override
    public void speak() { ... }      // 真的是覆寫,✅
}

漏寫 @Override 然後拼錯,會變成「定義了一個新方法」,bug 很難發現。

下一篇接 Java 另一個面向程式設計的核心——例外處理:checked vs unchecked、try-with-resources、何時該包裝何時該重拋。

Latest Updates

  • 2026.06.11 Content updated