1. 什麼是介面?
如果抽象類別是房子的藍圖,介面更像是一份合約或「契約」,用來要求完成特定的工作。比如你請水電工,你會期待他能「修水龍頭」與「排除漏水」。至於他要怎麼做—你不在意,重點是結果要達成。在 Java 中,介面正是這樣的契約:它說明必須實作哪些方法,但不告訴你如何實作。
重點速覽:
介面 是 Java 中的一種特殊型別,定義了一組方法;凡是簽署(實作)該介面的類別,都必須實作這些方法。
- 介面只描述「要做什麼」,而不是「怎麼做」。
- 在 Java 8 之前,介面不包含方法實作。
- 介面是純粹的契約:如果類別實作介面,就必須實作其所有方法。
為什麼這麼方便?
- 可以把多個介面「套用」到同一個類別上—也就是讓它同時扮演多種角色。
- 有助於建立彈性且可擴充的架構,讓類別能實作不同能力。
- 介面在 Java 標準程式庫中廣泛使用(例如 Comparable、Serializable、Runnable 等)。
2. 介面宣告的語法
在 Java 宣告介面—簡單至極。使用關鍵字 interface。在 Java 8 之前,介面方法預設視為 public abstract,即使沒有明寫。這表示:該方法必須在實作此介面的類別中予以實作。
介面範例
public interface Movable {
void move(int x, int y);
}
- 這裡我們宣告了介面 Movable(可理解為「可移動的」或「能移動的」)。
- 裡面宣告了方法 move(int x, int y)。沒有方法本體—只有簽章。這就是「契約」: 「如果你實作 Movable,就請實作 move」。
語法要點
- 介面中的方法在 Java 8 之前不包含本體。
- 介面中的所有方法預設皆為 public abstract(可以不必明寫)。
- 介面只能包含常數(public static final),不能有一般欄位。
常數範例
public interface Constants {
int MAX_SPEED = 100; // 預設即為 public static final
}
3. 介面與類別的差異
介面不是類別!來看看差別在哪裡。
| 類別(包含抽象類別) | 介面 |
|---|---|
| 可以包含欄位(狀態) | 不可包含欄位(只能有常數) |
| 可以包含方法實作 | 在 Java 8 之前介面不能包含實作,只有簽章 |
| 可以透過 new 建立實例(若非抽象) | 不能直接建立實例 |
| 只能單一繼承(extends) | 類別可以實作多個介面(implements) |
| 用來表達「它是什麼」 | 用來表達「它能做什麼」 |
類別透過 implements 來實作介面
public class Robot implements Movable {
@Override
public void move(int x, int y) {
System.out.println("機器人移動到點 (" + x + ", " + y + ")");
}
}
- 類別 Robot 實作了介面 Movable。
- 關鍵字 implements — 「實作」。
- 必須實作介面的所有方法(否則會有編譯錯誤)。
- 別忘了註解 @Override — 它不是必需,但能幫助編譯器與你避免失誤。
4. 介面使用範例
寫個簡單範例,看看實際如何運作。假設我們有介面 Movable,並希望不同類別都能「移動」:機器人、汽車、動物……
步驟 1:宣告介面
public interface Movable {
void move(int x, int y);
}
步驟 2:在類別中實作介面
public class Robot implements Movable {
@Override
public void move(int x, int y) {
System.out.println("機器人移動到點 (" + x + ", " + y + ")");
}
}
步驟 3:使用介面
public class Main {
public static void main(String[] args) {
Movable m = new Robot(); // 介面型別的變數!
m.move(10, 20); // 將輸出:機器人移動到點 (10, 20)
}
}
請注意
- 我們可以宣告介面型別的變數(Movable m),並將實作該介面的類別物件指派給它(new Robot())。
- 這使我們能撰寫通用的程式碼,能與任何「可移動」的物件合作,而不必知道它實際是哪個類別。
未實作方法時的編譯錯誤
Error: Class 'Robot' must either be declared abstract or implement abstract method 'move(int, int)' in 'Movable'
這就是介面的威力 — 它保證所有實作的類別都具備所需的方法。
5. Java 標準程式庫中的介面
介面不是「課本上的」概念而已。它們在整個 Java 標準程式庫中都被大量使用。以下是幾個例子:
- Comparable<T> — 用於比較物件的介面(例如用於排序)。
- Runnable — 啟動執行緒的介面。
- Serializable — 標記(marker)介面,表示物件可被序列化。
- List、Set、Map — 集合的介面。
範例:Comparable
public class Person implements Comparable<Person> {
String name;
int age;
// 建構子與其他方法...
@Override
public int compareTo(Person other) {
return this.age - other.age;
}
}
現在物件 Person 可以被排序,因為它們實作了介面 Comparable。
6. 視覺示意:介面如何運作
+-------------------+ +-------------------+
| interface | | class |
| Movable |<--------| Robot |
|-------------------| |-------------------|
| +move(int, int) | | +move(int, int) |
+-------------------+ +-------------------+
- 箭頭表示類別 Robot 實作了介面 Movable。
- 介面只規定「應該有什麼」,類別負責「如何運作」。
生活中的類比
在 Java 中,介面就像駕照。若你持有駕照(你實作了「駕駛員」這個介面),代表你會駕駛汽車。至於你怎麼開—有人小心、有人迅速—那是細節;重點是你已承諾自己會做這件事。
7. 實作範例:延續我們的應用
public interface Movable {
void move(int x, int y);
}
public class Animal implements Movable {
protected String name;
public Animal(String name) {
this.name = name;
}
@Override
public void move(int x, int y) {
System.out.println(name + " 移動到點 (" + x + ", " + y + ")");
}
}
public class Robot implements Movable {
private String model;
public Robot(String model) {
this.model = model;
}
@Override
public void move(int x, int y) {
System.out.println("機器人 " + model + " 開往座標 (" + x + ", " + y + ")");
}
}
public class Main {
public static void main(String[] args) {
Movable[] movables = {
new Animal("Barsik"),
new Robot("R2D2")
};
for (Movable m : movables) {
m.move(5, 10);
}
}
}
結果:
Barsik 移動到點 (5, 10)
機器人 R2D2 開往座標 (5, 10)
我們建立了一個 Movable 型別的物件陣列。裡面可以放入任何實作該介面的物件!迴圈中的程式碼不知道眼前的是動物還是機器人,但知道每個物件都會 move。
8. 使用介面時的常見錯誤
錯誤 1:嘗試直接建立介面的實例。 介面是契約,而非具體物件。不能寫 new Movable() — 這會導致編譯錯誤。應該建立實作該介面的類別的物件。
錯誤 2:沒有實作介面的所有方法。 若類別實作了介面,卻未實作其所有方法,編譯器會報錯:「Class must either be declared abstract or implement abstract method ...」。如果你不想實作所有方法—就把類別宣告為 abstract。
錯誤 3:忽略了存取修飾子。 介面的方法一律是 public(即使未明寫)。在實作的類別中不可降低存取層級,因此方法也必須是 public。
錯誤 4:試圖在介面中加入一般欄位。 介面只能宣告常數(public static final)。不能加入一般(非靜態)的欄位。
GO TO FULL VERSION