# 多型基本概念
多型表示利用父類別提供的方法呼叫,卻可以獲得子類別特有的行為。
class Animal{ | |
void move(){ | |
System.out.println("Animal moves!!!"); | |
} | |
} | |
class Dog extends Animal{ | |
void move(){ | |
System.out.println("Dog run!!!"); | |
} | |
} | |
class Bird extends Animal{ | |
void move(){ | |
System.out.println("Bird fly!!"); | |
} | |
} | |
class App{ | |
public static void main(String[] args){ | |
Animal animal = new Animal(); | |
Animal dog = new Dog(); | |
Animal bird = new Bird(); | |
animal.move(); | |
dog.move(); | |
bird.move(); | |
} | |
} |
變數 animal
用 Animal
的構建子宣告,這很符合常理。
變數 dog
就稍顯奇怪,以 Dog()
來初始化竟然可以用 Animal
來定義型態!
這是因為繼承的關係, Dog is Animal
。所以, Dog()
建構出來的物件會擁有 Dog
類別的成員,我們僅僅只是把這個物件當作 Animal
在看。
Animal moves!!! | |
Dog run!!! | |
Bird fly!!! |
雖然三者皆是由 Animal
做形態上的宣告,也都使用了 move()
作為方法,
但他實際上的本質不一,這就是多型的一種基本範例。
這樣的設計方式可以降低方法定義對類別的依賴,使用一個制定好的介面,利用該介面來操作不同的物件,增加程式的彈性及可維護性,設計上也比較有架構。
如果我們沒有多型的話,就必須針對不同物件設置不同的方法進行處理。
void AnimalMove(Animal animal){ | |
animal.move(); | |
} | |
void DogMove(Dog dog){ | |
dog.move(); | |
} | |
void BirdMove(Bird bird){ | |
bird.move(); | |
} |
# 隱性轉型
來看個簡單的範例:
class App { | |
public static void main(String[] args) { | |
Animal a = new Animal(); | |
Dog d = new Dog(); | |
Bird b = new Bird(); | |
moveAnimal(a); | |
moveAnimal(d); | |
moveAnimal(b); | |
} | |
static void moveAnimal(Animal ani){ | |
ani.move(); | |
} | |
} |
在上面程式中,我們定義了 moveAnimal(Animal animal)
的方法,他會接受一個 Animal
參數進來。同時的,Java 會幫你進行型態轉換,子類別必定擁有母類別的所有屬性、所有方法,所以子類別一定可以轉型為母類別,而不會出錯。
Dog d = new Dog(); | |
Animal a1 = d; // Java 幫你作了型態轉換,但你看不到,等價於下行 | |
Animal a2 = (Animal)d; // 自己寫是一樣的 | |
moveAnimal(d); // 等價於下行 | |
moveAnimal((Animal)d); |
因為這個機制,所以搭配多型的設計方法,程式撰寫上變得非常便利。
# 轉型失敗
以繼承來說,子類別是母類別的『延伸』擁有母類別的所有欄位、所有方法。
所以,子類別可以轉換成母類別。但,反之亦然嗎?
Animal ani = new Animal(); | |
Dog d = (Dog)ani; // 母類別強制轉型為子類別 | |
Exception in thread "main" java.lang.ClassCastException: | |
Animal cannot be cast to Dog |
當然的,執行的時候發生了錯誤,產生 ClassCastExeption
例外。