承上篇:
OOP:多型(Polymorphism) 以Java為例、
protected:Java為例
前言:這篇主要是探討Java中重新定義Override,根據參考資料自己做的筆記與心得,如日後有新發現都會陸續增加。
現在再審視一次我們所有的程式碼與專案
rpg Package內含RPG.java
Cast Package內含Magician.java SwordsMan.java Role.java
Role.java原始碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| package Cast;
public class Role {
private String name;
private int level;
private int blood;
public void setName(String name) {
this.name = name;
}
public void setLevel(int level) {
this.level = level;
}
public void setBlood(int blood) {
this.blood = blood;
}
public int getBlood() {
return blood;
}
public int getLevel() {
return level;
}
public String getName() {
return name;
}
}
|
SwordsMan.java原始碼:
1
2
3
4
5
6
| package Cast;
public class SwordsMan extends Role {
public void fight() {
System.out.println("揮劍攻擊");
}
}
|
Magician.java原始碼:
1
2
3
4
5
6
7
8
9
| package Cast;
public class Magician extends Role{
public void fight() {
System.out.println("魔法攻擊");
}
public void cure() {
System.out.println("魔法治療");
}
}
|
RPG.java原始碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| package rpg;
import Cast.Magician;
import Cast.Role;
import Cast.SwordsMan;
public class RPG {
public static void main(String[] args) {
SwordsMan swordsman = new SwordsMan();
swordsman.setName("Xanxus");
swordsman.setLevel(55);
swordsman.setBlood(1200);
Magician magician = new Magician();
magician.setName("Vortix");
magician.setLevel(131);
magician.setBlood(2750);
drawFight(swordsman);
}
public static void drawFight(Role role){
System.out.println(role.getName());
}
}
|
看到第18行的函式,現在我要根據我傳進去的職業,做出不同的攻擊,啊但是role.fight(); 會編譯失敗啊~~
因為Role class中沒有fight(),所以不能編譯,那這時怎麼辦?
這時就要用到@Override這東西,也就是重新定義實作。怎麼重新定義?
1.把子類別的方法拉出來,放到父類別中,並且內容為"空"!!像這樣:
1
2
3
4
5
6
| public class Role {
...略
public void fight() {
}
}
|
2.重新定義子類別:
1
2
3
4
5
6
| package Cast;
public class SwordsMan extends Role {
public void fight() {
System.out.println("揮劍攻擊");
}
}
|
這不是跟原本一樣嗎?是的。它的重新定義指說:
在繼承父類別之後,定義與父類別中相同的方法簽署,但實作內容不同,這稱為重新定義(Override)。
白一點,如果父類別想要擁有使用子類別的method,那只要子類別的method介面一樣,就可以直接在父類別做一個與子類別相同的method但內容為空就好,不用實作,實作靠子類別去做,實作內容看子類別而定。
由現有程式碼來看,Role想要用fight()但它沒有,那就在Role裡做一個fight(),就可以用了,操作只要靠SwordsMan上的方法定義。
現在可以這樣用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| package rpg;
import Cast.Magician;
import Cast.Role;
import Cast.SwordsMan;
public class RPG {
public static void main(String[] args) {
SwordsMan swordsman = new SwordsMan();
swordsman.setName("Xanxus");
swordsman.setLevel(55);
swordsman.setBlood(1200);
drawFight(swordsman);
}
public static void drawFight(Role role){
System.out.print(role.getName());
role.fight();
}
}
|
run:
Xanxus揮劍攻擊
而通常如果子類別重新定義了父類中的method,可在子類前的method加一行@Override ,這樣會要求編譯器檢查,這個method是不是重新定義了父類中某method,如果沒有,就會錯誤。
像現在我把Role的fight()拿掉,它就錯了。
如果你不想你的方法被重新定義Override,那就在method前加final修飾字,這樣想Override你method的人就會編譯錯誤。
final int methodA{
//........
}
關鍵字super:透過它,子類別可取得父類別中的方法定義,於呼叫前加上super。
如果原本Role就有toString()
1
2
3
4
5
6
7
| public abstract class Role {
...略
public String toString() {
return String.format("(%s, %d, %d)", this.name,
this.level, this.blood);
}
}
|
透過super取得父類別定義的方法,串接字串:
1
2
3
4
5
6
7
| public class SwordsMan extends Role {
.............................
@Override
public String toString() {
return "劍士 " + super.toString();
}
}
|
這裡要注意的是,如果父類別方法是public,那最好子類別取得父類方法的方法也要public,原則是權限只能擴大不能縮小。因為如果父類的方法是private,子類public就會編譯錯誤!
如果在Role class 建了可以呼叫figth()的方法,正常是呼叫到了子類別的fight,因為實例是子類別,可是如果想在Role裡面呼叫figth()的方法,那個figth想要是Role的figth(),可以使用super嗎
回覆刪除