[toc] https://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html # interface ## why do we need interface? 有很多時候, 會想要把 標準/實作 分離。 一個範例: 一台印表機,可能都有"列印"的功能。 作為印表機的使用者,你不需要知道底層是如何運作的,只要功能能用就行了。 這是因為所有的印表機都遵守了一個共同的**「介面規範」**,確保所有印表機都具備這些基本功能。 這樣一來,無論你用哪台印表機,都能用相同的方式來操作,而不需要學習不同的控制方法。 同樣, 在Java, 介面就是這樣,確保實作同一個介面的類別能互相溝通。 ## in Java interface(介面) 可以說是一個Method Set template 但是你仍然算是宣告一個參考資料型態 你還是可以到處使用interface Name。 --- ## Abstract Method https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html 是一個無實作的方法(無Method Body, 用`;` 改寫) 必須在abstract class/interface裡面 ```java abstract void print(String s); ``` --- ### Members member 可以有: - default method(不能被 `static`/`final`/`private`/`protected`修飾) - 有預設的實作 - 可以被子類別實作 ```java interface IPrinter { default void print(String s) { System.out.println(s); } } class TypeA implements IPrinter { @Override public void print(String s) { System.out.println("[MyPrinter]" + s); } } class TypeB implements IPrinter { // it use the Printer's default print(String s) } class Main { public static void main(String[] args) { TypeA t = new TypeA(); t.print("hello"); // [MyPrinter] hello TypeB t2 = new TypeB(); t2.print("world"); // world } } ``` - abstract method (不能被 `static`/`default`/`final`/修飾) - 在Interface中 不能被`private`/`protected`修飾, `default` 會變為 `public` - 必須被子類別實作 - 在Interface中無須`abstract`修飾 - static method - `default` 會變為 `public` - 效果與class的static method一樣。 - private method - 無法被子類別實作的輔助方法 - variable - 都會是`public static final` - 不能是`private` / `protected` --- 範例: variable / static method 這些static的成員不常放在interface裡面。 ```java interface TestInterface { int i = 1; // 預設會 public static final private void helperMethod() { // private method } static void hello() { // static method System.out.println("Hello"); } } class Main { public static void main(String[] args) { int i = TestInterface.i; TestInterface.hello(); } } ``` --- 範例: ```java= interface IPrinter { void print(String s); } class TypeA implements IPrinter { @Override public void print(String s) { System.out.println("[A] " + s); } } class TypeB implements IPrinter { @Override public void print(String s) { System.out.println("[B] " + s); } } public class Main { public static void main(String[] args) { // 變數型態用Interface Printer a = new TypeA(); a.print("test"); // [A] test // 變數型態用自身的class TypeB b = new TypeB(); b.print("test"); // [B] test } } ``` ## 變數形態要用介面還是類別? 你說上面的範例, 宣告變數時, 使用Interface還是用Class ? 因為a, b 都是 Printer, 所以可以放進來很合理 ```java public class Main { public static void main(String[] args) { Printer a = new TypeA(); TypeB b = new TypeB(); printHelloWorld(a); printHelloWorld(b); } public static void printHelloWorld(Printer c) { c.print("Hello World"); } } ``` 正因為如此, 如果底層把印表機的邏輯寫好, 把底層的getPrinter寫好, 在比較上層的程式碼, 我們可以不在乎印表機是誰。 透過介面提供的方法操作。 讓程式碼與實作的各種(印表機)類別解耦。 ```java class PrinterManager { private static Printer typeB = new TypeB(); private static Printer typeA = new TypeA(); public static Printer getPrinter() { // 這裡可能會找一台沒人在用的Printer之類的 while(...) { if (...) return typeB; else if (...) return typeA; } } } public class Main { public static void main(String[] args) { Printer a = PrinterManager.getPrinter(); a.print("hello"); // 用就對了 } } ``` ## interface 繼承 interface 假設interface A extends interface B 如果有個class C implements A - 等於class C implements A, B (Interface 能 extend 多個 Interface) ```java interface Movable { void move(int x, int y); } interface Runnable extends Movable { void run(int speed); } class Human implements { // move // run } ``` class 能 implement 多個interface ```java interface Movable { void move(int x, int y); } interface Runnable { void run(int speed); } class Human implements Movable, Runnable { // move // run } ```