介面

      在〈介面〉中尚無留言

介面(Interface)

完全不相關的類別,卻擁有相同的功能。比如鳥跟飛機,一個是生物,一個是機械,但卻同樣擁有 “飛” 的功能。這有種群組的功能。

另外也可以想成二個完全不相關的類別,但擁有相同的方法,此時可以用 Interface 讓每個類別實作。

這種觀念有點像具某種功能一樣. 比如皮卡丘是神奇寶貝, 是爬蟲類. 而劍魚也是神奇寶貝, 但屬於水中生物.

其實介面是為了彌補 Java 單一繼承的缺陷,也就是多型。所以在有多重繼承的語言中,比如 Python 就沒有interface。

介面同時也跟抽象類別一樣,規定繼承者必需遵守的契約。

interface Land{
    void walk();
}
interface Water{
    void swin();
}
abstract class Pokemon{
    abstract public void setLevel(int l);
}
class Pikachi extends Pokemon implements Land{
    @Override
    public void walk() {
        System.out.println("用爬的");
    }
    @Override
    public void setLevel(int level){}
}
class Fish extends Pokemon implements Water{
    @Override
    public void swin() {
        System.out.println("用游的");
    }
    public void setLevel(int level){}
}

interface 類別修飾子

interface 如果跟主程式同一個檔或同一個 package,有沒有加 public 都沒關係,如下所示,新增一個 Frog.java 檔,然後 interface 不需加任何修飾子

public class Frog implements Water{
    @Override
    public void swin() {
        System.out.println("走路");
    }
}
interface Water {
    void swin();
}

但上述說明通常不常發生,因為 interface 都位於獨立的 package,然後供給其它 package 使用,所以正確的寫法是新增一個 Water.java 檔,interface 前面要加上 public。

package net.ddns.mahaljsp;
public interface Water {
    void swin();
}

然後新增 Frog.java,class 之前也要加 public

package net.ddns.mahaljsp;
public class Frog implements Water{
    @Override
    public void swin() {
        System.out.println("走路");
    }
}

而主程式則抧寫如下

package filepath;
import net.ddns.mahaljsp.Frog;
import net.ddns.mahaljsp.Water;
import net.ddns.mahaljsp.os;

public class Test2 {
    public static void main(String[] args){
        os.utf8();
        Water f=new Frog();
        f.swin();
    }
}

interface 方法修飾子

interface 中的方法,一定是 abstract public,系統會自動加入,也可以手動加入。不過請注意,C# 不允許雞婆的手動加入。

若介面的抽象方法宣告為 private or protected,則會編譯錯誤

    public interface Returnable{
        abstract public String doReturn();
    }

子類別實作

子類別繼承了介面,此時的關鍵字就不再是 extends ,而是 implements。

class Pikachu implements Land{}

此時的 Pikachu 就必需實作 Land 的所有抽象方法。

實作多個介面

為什麼要實作多個介面呢?? 讓我們思考一下青蛙 class Frog,它到底是要實作 Land 還是 Water? 青蛙是兩棲生物,所以當然是一起實作多個介面,中間以 “,” 隔開。

interface Land{}
interface Water{}
class Frog implements Land, Water{}

抽象類別與介面同時實作

類別可以在繼承類別或抽象類別時,又同時實作多個介面。但此類別就必需實作抽象類別及所有介面的所有抽象方法。

abstract class Pokemon{
    public int level;
    protected abstract void setLevel(int l);
}
interface Land{
    void setWalk();
}
interface Water{
    void setSwinning();
}
class Frog extends Pokemon implements Land, Water{
    @Override
    protected void setLevel(int l) {}
    @Override
    public void setWalk() {}
    @Override
    public void setSwinning() {}
}

多型

若要使用 interface 裏的方法,則物件參考必需是此 Interface 或是 implement 此介面的類別才可以,若物件參考是沒實作此介面的類別則無法存取

  public static void main(String[] args) {
      Pokemon p1=new Pikachi();
      //p1.walk();
      Pikachi p2=new Pikachi();
      p2.walk();
  }

p1 屬 Pokemon,跟 Land 沒關係,所以不能使用 walk();
p2 屬 Pikachi,is a Land,所以可以使用walk();

 介面的變數

介面內的變數,一定是常數欄位(constant fields),系統會自動視為 public static final 變數,所以變數都要自行給定初始值。

    interface Running{
        public static final String WARNING="這是爬蟲類";
        public void run();
    }

 介面繼承

青蛙是兩棲生物,所以實作了 Land 及 Water 二個介面。那可以將 Land 及 Water 變成一個 Amphibian 介面,再給青蛙實作嗎? 是的,介面可以繼承介面,而且是可以多重繼承的。 

請注意喔,介面的繼承是 extends。

abstract class Pokemon{
    public int level;
    protected abstract void setLevel(int l);
}
interface Land{
    void setWalk();
}
interface Water{
    void setSwinning();
}
interface Amphibian extends Land, Water{}
class Frog extends Pokemon implements Amphibian{
    @Override
    protected void setLevel(int l) {}
    @Override
    public void setWalk() {}
    @Override
    public void setSwinning() {}
}

介面與抽象類別的抽象方法相衝

類別可以 implements 多個介面。試想若每個介面都有相同的方法時,那類別要怎麼實作? 其實不相衝,只要實作一個就好。

預設物件方法

自 Java 8 開始可以實作方法,但必需標示為 default,如下所示。

package net.ddns.mahaljsp;
public interface Water {
    void swin();
    default public void turbo(){
        System.out.println("加速");
    }
}

Frog 實作 Water 時,可以覆蓋  turbo()。若沒有覆蓋 turbo,則使用 Water 介面的 turbo。

package net.ddns.mahaljsp;
public class Frog implements Water{
    @Override
    public void swin() {
        System.out.println("游泳");
    }
    //底下可有可無
    @Override
    public void turbo(){
        System.out.println("青蛙加速");
    }
}

介面類別方法

Java 8 也允許實作類別方法

package net.ddns.mahaljsp;
public interface Water {
    void swin();
    public static void print(String s){
        System.out.println(s);
    }
}

主程式調用介面類別方法,只能使用「介面.類別」,如下所示

public class Test {
    public static void main(String[] args){
        os.utf8();
        Water.print("Hello");
    }
}

類別方法是把相關的工具方法都放回介面中,提高內聚性(cohesion)

考題

有二個介面及一個抽象類別
interface Land{}
interface Water{}
abstract class Pokemon{}
請問以下何者是正確的
1. class Frog implements Pokemon{}
2. class Frog extends Pokemon{}
3. class Frog extends Land{}
4. class Frog implements Land, Water{} 
5. class Frog extends Pokemon implements Land, Water{}
6. interface Amphibian implements Land{}
7. interface Amphibian extends Land, Water{}
Ans:
2, 4, 5, 7

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *