---
# System prepended metadata

title: interface
tags: [Java]

---

[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
}
```

