Java 介面 (Interface)

介面定義一組方法規格,類別可以實作介面來保證具有特定的行為。

基本語法

使用 interface 定義,implements 實作:

// 定義介面
public interface Drawable {
    void draw();
}

// 實作介面
public class Circle implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing a circle");
    }
}

介面的特點

  • 方法預設是 public abstract
  • 變數預設是 public static final(常數)
  • 不能有建構子
  • 類別可以實作多個介面
public interface Animal {
    // 常數(自動加上 public static final)
    int MAX_AGE = 100;
    
    // 抽象方法(自動加上 public abstract)
    void eat();
    void sleep();
}

實作多個介面

public interface Swimmable {
    void swim();
}

public interface Flyable {
    void fly();
}

// 實作多個介面
public class Duck implements Swimmable, Flyable {
    @Override
    public void swim() {
        System.out.println("Duck is swimming");
    }
    
    @Override
    public void fly() {
        System.out.println("Duck is flying");
    }
}

繼承類別同時實作介面

public class Animal {
    protected String name;
}

public interface Pet {
    void play();
}

// 先 extends 再 implements
public class Dog extends Animal implements Pet {
    @Override
    public void play() {
        System.out.println(name + " is playing");
    }
}

default 方法 (Java 8+)

介面可以有預設實作:

public interface Vehicle {
    void start();
    
    // default 方法
    default void stop() {
        System.out.println("Vehicle stopped");
    }
}

public class Car implements Vehicle {
    @Override
    public void start() {
        System.out.println("Car started");
    }
    // stop() 使用預設實作
}

static 方法 (Java 8+)

public interface StringUtils {
    static boolean isEmpty(String s) {
        return s == null || s.isEmpty();
    }
}

// 使用介面名稱呼叫
boolean empty = StringUtils.isEmpty("");  // true

private 方法 (Java 9+)

介面內部使用的私有方法:

public interface Calculator {
    default int addAndDouble(int a, int b) {
        return doubleIt(a + b);
    }
    
    default int subtractAndDouble(int a, int b) {
        return doubleIt(a - b);
    }
    
    // 私有方法,供 default 方法使用
    private int doubleIt(int n) {
        return n * 2;
    }
}

介面繼承

介面可以繼承其他介面:

public interface Animal {
    void eat();
}

public interface Pet extends Animal {
    void play();
}

// 實作 Pet 需要實作兩個方法
public class Dog implements Pet {
    @Override
    public void eat() { }
    
    @Override
    public void play() { }
}

常用介面

Comparable

public class Student implements Comparable<Student> {
    private String name;
    private int score;
    
    @Override
    public int compareTo(Student other) {
        return this.score - other.score;
    }
}

// 可以排序
List<Student> students = new ArrayList<>();
Collections.sort(students);

Cloneable

public class Person implements Cloneable {
    private String name;
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

函數式介面 (Java 8+)

只有一個抽象方法的介面,可以用 Lambda:

@FunctionalInterface
public interface Calculator {
    int calculate(int a, int b);
}

// 使用 Lambda
Calculator add = (a, b) -> a + b;
Calculator multiply = (a, b) -> a * b;

System.out.println(add.calculate(5, 3));       // 8
System.out.println(multiply.calculate(5, 3));  // 15

實際應用

策略模式

public interface PaymentStrategy {
    void pay(double amount);
}

public class CreditCardPayment implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("信用卡支付 $" + amount);
    }
}

public class PayPalPayment implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("PayPal 支付 $" + amount);
    }
}

// 使用
public void checkout(PaymentStrategy strategy, double amount) {
    strategy.pay(amount);
}

回呼 (Callback)

public interface OnClickListener {
    void onClick();
}

public class Button {
    private OnClickListener listener;
    
    public void setOnClickListener(OnClickListener listener) {
        this.listener = listener;
    }
    
    public void click() {
        if (listener != null) {
            listener.onClick();
        }
    }
}

// 使用
button.setOnClickListener(() -> System.out.println("按鈕被點擊"));

介面 vs 抽象類別

更詳細的比較請參考 Java 抽象類別 vs 介面