介面(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
