為了要操作物件,您必須得知物件上所公開的(public)操作介面,即使是繼承關係上的父子類別,透過父類別型態所宣告的名稱,也只能操作父類別中有宣告的公開方法,對於子類別中所新定義的方法並無法操作。
透過定義抽象方法來規範公開的操作介面只是一個解決的方法,由於在 Java 中只能單一繼承,也就是一次只能繼承一個類別,對於非該類別繼承體系的物件,定義抽象方法並無法解決問題。
在 Java 中介面( interface )用來規範公開的操作介面,一個實作介面的某類別,必須實作介面中所有已規範的操作方法,一個類別可以實作多個介面,這表示一個類別可以身兼多個角色與職責。
考慮您有一個物件容器,您可以將「任何」物件儲存至該容器中,您希望容器被加入物件時,都可以在螢幕上顯示一段招呼語,而任何物件被從容器移除時,也可以顯示一段訊息顯示物件已經離開容器。
注意需求所說的是「任何」物件,所以您無法使用抽象類別事先定義好抽象方法來滿足這個需求,因為您並無法得知被加入容器的物件是屬於哪一個類別。
在 Java 中您可以使用介面(interface)來解決這個需求,定義介面的的關鍵字是 interface,語法則如下所示:
[modifier1] interface interface_identifier { [modifier2] type method_identifier(type param..); }
其中:
以實際的例子來看看如何定義一個介面,如程式碼 12-1 所示:
public interface ContainerListener { public void doHello(); public void doGoodbye(); }程式碼 12-1 ContainerListener.java
在第 2 行與第 3 行只定義了方法權限、返回值型態、方法名稱與空的參數列,而不用實作方法本體,撰寫介面時也是以*.java 檔案撰寫,編譯過後也是產生*.class 檔案。
表面上看來,介面好像完全沒有任何實作本體的方法集合,類似於類別本體都是抽象方法的抽象類別,但事實並不是如此,「繼承某抽象類別的類別必定是該類別的一個子類」,但「實作某介面的類別並不被歸屬於哪一類」,一個類別上可以實作多個介面。
在定義類別時,可以一併使用 implements 關鍵字來指定要實作的介面,例如設計兩個類別,它們都實作了ContainerListener,會在被加入某個容器或被移除時顯示訊息,直接以程式碼 12-2、12-3 作為示範:
public class Some implements ContainerListener { public void doHello() { System.out.println("Some 物件被加入..."); } public void doGoodbye() { System.out.println("Some 物件被移除..."); } }程式碼 12-2 Some.java
public class Other implements ContainerListener{ public void doHello() { System.out.println("Other 物件被加入..."); } public void doGoodbye() { System.out.println("Other 物件被移除..."); } }程式碼 12-3 Other.java
可以看到 Some 與 Other 兩個不同的類別,都以 implements 實作了 ContainerListener 介面,它們都必須遵守 ContainerListener 介面的規範:實作 doHello() 與doGoodbye()兩個方法。
當您取得實作介面的某個物件之後,您可以將它的操作介面轉換為所實作的介面,如此就可以使用介面上所規範的方法來操作物件,例如程式碼 12-4 實作一個簡單的容器,物件的加入或移除都會呼叫 doHello()與 doGoodbye()方法。
public class SimpleContainer { private Object[] objArr; private int index = 0; // 預設 10 個物件空間 public SimpleContainer() { objArr = new Object[10]; } public SimpleContainer(int capacity) { objArr = new Object[capacity]; } // 加入物件 public void add(Object o) { // 轉換操作介面 ContainerListener listener = (ContainerListener) o; // 呼叫介面上規範的方法 listener.doHello(); objArr[index] = o; index++; } // 移除物件 public void remove(int i) { // 轉換操作介面 ContainerListener listener = (ContainerListener) get(i); objArr[i] = null; // 呼叫介面上規範的方法 listener.doGoodbye(); } public int length() { return index; } public Object get(int i) { return objArr[i]; } public static void main(String[] args) { SimpleContainer container = new SimpleContainer(4); // 加入物件 container.add(new Some()); container.add(new Other()); container.add(new Some()); container.add(new Other()); System.out.println(); // 移除物件 container.remove(0); container.remove(1); container.remove(2); container.remove(3); } }程式碼 12-4 SimpleContainer.java
執行結果如下所示:
雖然 Some 與 Other 兩個是不同的類別,但由於它們都實作了 ContainerListener 介面,因而在 SimpleContaner 類別的add()與 remove()方法中,都可以在轉換操作介面之後,順利的操作 Some 物件與 Other 物件的 doHello() 與doGoodbye()方法。
介面也可以進行繼承的動作,同樣也是使用"extends"關鍵字,例如:
public interface 名稱 extends 介面 1, 介面 2 { // ... }
不同於類別的是,介面可以同時繼承多個介面,如果有一個A 介面繼承了 B、C 介面,則實作 A 介面的類別,對於 B、C 介面中規範的方法也必須一併實作。