介面
什麼是Interface?
介面(Interface)可以想成是「功能」,但功能的內容由實作(implements)的類別自己去完成。
實作介面的子類別,這個關係有點像是繼承,但不能把這個稱為繼承。
有一個Fly飛的功能,飛機去實作怎麼飛的功能,可以把飛機說它是一個Fly飛嗎?
只能說飛機可以像鳥一樣飛,Fly like a bird。
這是一個like a的關係,像…什麼什麼…一樣,有它的功能。
不能因為鳥有飛的功能,就把飛機繼承鳥。
1
2
3
class AirPlane extends Bird {
}
飛機跟鳥,不是Is A(是一個),飛機不是一個鳥。
但飛機可以像鳥一樣飛,是Like A(像一個)的關係。
建立介面Interface
使用關鍵字interface來宣告這是一個介面(Interface),這個介面(Interface)的名字是Fly。
1
2
public interface Fly {
}
屬性
介面的屬性存取權限一定是public,只能是final與static,final是無法再被實作的子類別修改,static是靜態屬性,static + final就是常數constant。
可以省略public final static,編譯會自動加上。
1
2
3
4
5
public interface Fly {
public final static int VERSION = 1;
// 上面這句與以下相等,二者是相同意思。
// int VERSION = 1;
}
使用介面.屬性
1
System.out.println(Fly.VERSION);
無法再被更改。
1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
System.out.println(Fly.VERSION);
// 以下會編譯失敗,因為是final,不可再被更改。
Fly.VERSION = "addfdf";
}
}
抽象方法
介面中的方法不寫內容,所以用分號;
來結尾,由子類別去實作方法。
抽象方法存取權限一定是public,因為設為private就沒有辦法給子類別實作。
編譯器會自動加上為方法加上public、abstract。
1
2
3
4
5
public interface Fly {
void fly();
// 上面這句與以下相等,二者是相同意思。
// public abstract void fly();
}
實作
所謂的實作就是把介面的抽象方法覆蓋掉,覆寫一個屬於自己的方法,即便內容是空的,只有花括號{}
包住,也是覆寫。
使用implements
關鍵字實作Fly介面,並且一定要覆寫(Override)抽象方法fly()
1
2
3
4
5
6
public class Airplane implements Fly{
@Override
public void fly() {
// 即便內容是空的,只有花括號包住,也是覆寫。
}
}
實作多個Interface
implements Fly, Swim
以上語法使用逗號隔開不同介面,Fly, Swim都是介面(Interface)。
1
2
3
4
5
6
7
8
public class Duck implements Fly, Swim{
// 覆寫Fly介面的fly()方法
@Override
public void fly() {}
@Override
public void swim() {}
}
介面的範例
飛的功能
1
2
3
public interface Fly {
void fly();
}
游泳的功能
1
2
3
public interface Swim {
void swim();
}
飛機實作飛的功能
1
2
3
4
5
6
public class AirPlane implements Fly {
@Override
public void fly() {
System.out.println("飛機用引擎飛");
}
}
鴨子實作飛與游泳的功能
1
2
3
4
5
6
7
8
9
10
11
public class Duck implements Fly, Swim{
@Override
public void fly() {
System.out.println("鴨子用翅膀飛");
}
@Override
public void swim() {
System.out.println("鴨子用腳掌划");
}
}
狗實作游泳的功能
1
2
3
4
5
6
public class Dog implements Swim {
@Override
public void swim() {
System.out.println("狗游狗爬式");
}
}
潛水艇實作游泳功能
1
2
3
4
5
6
public class Submarine implements Swim{
@Override
public void swim() {
System.out.println("潛水艇會潛水");
}
}
測試程式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Test {
public static void main(String[] args) {
AirPlane airPlane = new AirPlane();
airPlane.fly();
Duck duck = new Duck();
duck.swim();
duck.fly();
Submarine submarine = new Submarine();
submarine.swim();
Dog dog = new Dog();
dog.swim();
}
}
飛機用引擎飛
鴨子會游泳
鴨子用翅膀飛
潛水艇會潛水
狗游狗爬式
多型
什麼是編譯類型?什麼是執行類型?
下方的程式碼,等號左邊是編譯類型,等號右邊是執行類型。
1
2
3
編譯類型 = 執行類型
Fly bird = new Bird();
Fly airplane = new Airplane();
介面作為類型,可以指向實作Fly介面的子類別。
雖然編譯類型是介面,但執行時指向的是實作介面的子類別。
呼叫介面的fly(),實際上是呼叫子類別的fly()。
1
2
Fly bird = new Bird();
bird.fly();
介面多型陣列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Test {
public static void main(String[] args) {
// 介面作為類型,只要是實作Fly的子類別都可以放進這個陣列
Fly[] arr = new Fly[2];
arr[0] = new AirPlane();
arr[1] = new Bird();
for (Fly obj : arr) {
obj.fly();
}
}
}
class AirPlane implements Fly {
@Override
public void fly() {
System.out.println("飛機飛");
}
}
class Bird implements Fly {
@Override
public void fly() {
System.out.println("鳥會飛");
}
}
飛機飛
鳥會飛
判斷子類別
飛機有一個呼叫塔台的功能。
1
2
3
4
5
6
7
8
9
10
class AirPlane implements Fly {
@Override
public void fly() {
System.out.println("飛機飛");
}
public void call() {
System.out.println("呼叫塔台");
}
}
使用instanceof與強制轉型成子類別,就可以呼叫子類別的方法。因為Fly介面只有fly()方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test {
public static void main(String[] args) {
Fly[] arr = new Fly[2];
arr[0] = new AirPlane();
arr[1] = new Bird();
for (Fly obj : arr) {
if (obj instanceof AirPlane) {
((AirPlane) obj).call();
}
obj.fly();
}
}
}
介面的多型(參數)
寫一個fly()方法,參數是有實作Fly的類別都可以放進來。
寫一個Swim()方法,參數是有實作Swim的類別都可以放進來。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Test {
public void fly(Fly something) {
something.fly();
}
public void swim(Swim something) {
something.swim();
}
public static void main(String[] args) {
Test test = new Test();
test.fly(new AirPlane());
test.fly(new Duck());
test.swim(new Duck());
test.swim(new Submarine());
test.swim(new Dog());
}
}
飛機用引擎飛
鴨子用翅膀飛
鴨子會游泳
潛水艇會潛水
狗游狗爬式
由以上可以發現,介面跟繼承是完全不同的概念,類別(AirPlane)實作介面(Fly)的抽象方法(fly),AirPlane就是介面(Fly)。
介面的多型
建立一個Operator運算子的介面,介面中有抽象的計算方法calculate()
Operator.java
1
2
3
4
// 運算子
public interface Operator {
int calculate(int x, int y);
}
加法運算子,實作Operator介面,覆寫calculate()方法
1
2
3
4
5
6
public class Add implements Operator{
@Override
public int calculate(int x, int y) {
return x + y;
}
}
減法運算子,實作Operator介面,覆寫calculate()方法
1
2
3
4
5
6
public class Minus implements Operator{
@Override
public int calculate(int x, int y) {
return x - y;
}
}
乘法運算子,實作Operator介面,覆寫calculate()方法
1
2
3
4
5
6
public class Multiply implements Operator{
@Override
public int calculate(int x, int y) {
return x * y;
}
}
計算機,注意!calculate的第1個參數是Operator介面,也就是只要有實作Operator的類別(加法運算子、減法運算子、乘法運算子)都可以丟進去。
1
2
3
4
5
public class Calculator {
public int calculate(Operator operator, int x, int y) {
return operator.calculate(x,y);
}
}
主程式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {
// 建立計算機
Calculator calculator = new Calculator();
int x = 10;
int y = 5;
// 加法,第1個參數把實作Operator介面的Add類別丟進去
int add_result = calculator.calculate(new Add(), x, y);
System.out.println(x + "+" + y + " = " + add_result);
// 減法,第1個參數把實作Operator介面的Minus類別丟進去
int minus_result = calculator.calculate(new Minus(), x, y);
System.out.println(x + "-" + y + " = " + minus_result);
// 乘法,第1個參數把實作Operator介面的Multiply類別丟進去
int multiply_result = calculator.calculate(new Multiply(), x, y);
System.out.println(x + "*" + y + " = " + multiply_result);
}
10+5 = 15
10-5 = 5
10*5 = 50
由上面例子發現,Operator介面可以是Add,可以是Minus、Multiply,類別只要實作Operator介面,這個類別就是Operator。
Interface的default方法、static方法
jdk1.8之後有default方法、static方法。
前面有提過,介面有一點像繼承的關係,但又不是繼承,因為有一點像繼承,所以實作介面的子類別,都會自動擁有父介面的方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface Fly {
int VERSION = 0;
// 抽象方法
void fly();
// default方法
default void dosomething() {
fly();
}
// 靜態方法
static void print() {
System.out.println(VERSION);
}
}
鳥實作Fly介面。
1
2
3
4
5
6
class Bird implements Fly {
@Override
public void fly() {
System.out.println("鳥會飛");
}
}
測試
1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
Bird bird = new Bird();
// 鳥類擁有介面的屬性與方法
bird.dosomething();
}
}
鳥會飛
但物件沒有擁有介面的屬性,使用介面的屬性,仍是要用「類別.介面屬性」或「介面.屬性」。
1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
Fly bird = new Bird();
System.out.println(Bird.VERSION);
}
}