Java 多態(tài)
本小節(jié)我們來(lái)學(xué)習(xí)面向?qū)ο蟮淖詈笠淮筇卣鳌鄳B(tài)。多態(tài)是面向?qū)ο笞钪匾奶匦浴N覀儗⒔榻B多態(tài)的概念和特點(diǎn),并帶領(lǐng)大家實(shí)現(xiàn)一個(gè)多態(tài)的案例,你將了解到多態(tài)的實(shí)現(xiàn)條件、什么是向上轉(zhuǎn)型以及什么是向下轉(zhuǎn)型,并學(xué)會(huì)使用instanceof運(yùn)算符來(lái)檢查對(duì)象引用是否是類(lèi)型的實(shí)例。
1. 概念和特點(diǎn)
多態(tài)顧名思義就是多種形態(tài),是指對(duì)象能夠有多種形態(tài)。在面向?qū)ο笾凶畛S玫亩鄳B(tài)性發(fā)生在當(dāng)父類(lèi)引用指向子類(lèi)對(duì)象時(shí)。在面向?qū)ο缶幊讨校^多態(tài)意指相同的消息給予不同的對(duì)象會(huì)引發(fā)不同的動(dòng)作。換句話(huà)說(shuō):多態(tài)意味著允許不同類(lèi)的對(duì)象對(duì)同一消息做出不同的響應(yīng)。
例如,火車(chē)類(lèi)和飛機(jī)類(lèi)都繼承自交通工具類(lèi),這些類(lèi)下都有各自的run()方法,交通工具的run()方法輸出交通工具可以運(yùn)輸,而火車(chē)的run()方法輸出火車(chē)會(huì)跑,飛機(jī)的run()方法則輸出飛機(jī)會(huì)飛,火車(chē)和飛機(jī)都繼承父類(lèi)的run()方法,但是對(duì)于不同的對(duì)象,擁有不同的操作。
任何可以通過(guò)多個(gè)IS-A測(cè)試的 Java 對(duì)象都被視為多態(tài)的。在 Java 中,所有 Java 對(duì)象都是多態(tài)的,因?yàn)槿魏螌?duì)象都能夠通過(guò)IS-A測(cè)試以獲取其自身類(lèi)型和 Object 類(lèi)。
2. 實(shí)現(xiàn)多態(tài)
2.1 實(shí)現(xiàn)條件
在 Java 中實(shí)現(xiàn)多態(tài)有 3 個(gè)必要條件:
- 滿(mǎn)足繼承關(guān)系
- 要有重寫(xiě)
- 父類(lèi)引用指向子類(lèi)對(duì)象
2.1 實(shí)例
例如,有三個(gè)類(lèi)Pet、Dog、Cat:
父類(lèi)Pet:
class Pet {
// 定義方法 eat
public void eat() {
System.out.println("寵物吃東西");
}
}
子類(lèi)Dog繼承Pet
class Dog extends Pet { // 繼承父類(lèi)
// 重寫(xiě)父類(lèi)方法 eat
public void eat() {
System.out.println("狗狗吃狗糧");
}
}
子類(lèi)Cat繼承Pet
class Cat extends Pet { // 繼承父類(lèi)
// 重寫(xiě)父類(lèi)方法 eat
public void eat() {
System.out.println("貓貓吃貓糧");
}
}
在代碼中,我們看到Dog和Cat類(lèi)繼承自Pet類(lèi),并且都重寫(xiě)了其eat方法。
現(xiàn)在已經(jīng)滿(mǎn)足了實(shí)現(xiàn)多態(tài)的前兩個(gè)條件,那么如何讓父類(lèi)引用指向子類(lèi)對(duì)象呢?我們?cè)?code>main方法中編寫(xiě)代碼:
public void main(String[] args) {
// 分別實(shí)例化三個(gè)對(duì)象,并且保持其類(lèi)型為父類(lèi)Pet
Pet pet = new Pet();
Pet dog = new Dog();
Pet cat = new Cat();
// 調(diào)用對(duì)象下方法
pet.eat();
dog.eat();
cat.eat();
}
運(yùn)行結(jié)果:
寵物吃東西
狗狗吃狗糧
貓貓吃貓糧
在代碼中,Pet dog = new Dog();、Pet cat = new Cat();這兩個(gè)語(yǔ)句,把Dog和Cat對(duì)象轉(zhuǎn)換為Pet對(duì)象,這種把一個(gè)子類(lèi)對(duì)象轉(zhuǎn)型為父類(lèi)對(duì)象的做法稱(chēng)為向上轉(zhuǎn)型。父類(lèi)引用指向了子類(lèi)的實(shí)例。也就實(shí)現(xiàn)了多態(tài)。
2.3 向上轉(zhuǎn)型
向上轉(zhuǎn)型又稱(chēng)為自動(dòng)轉(zhuǎn)型、隱式轉(zhuǎn)型。向上轉(zhuǎn)型就是父類(lèi)引用指向子類(lèi)實(shí)例,也就是子類(lèi)的對(duì)象可以賦值給父類(lèi)對(duì)象。例如:
Pet dog = new Dog();
這個(gè)是因?yàn)?code>Dog類(lèi)繼承自Pet類(lèi),它擁有父類(lèi)Pet的全部功能,所以如果Pet類(lèi)型的變量指向了其子類(lèi)Dog的實(shí)例,是不會(huì)出現(xiàn)問(wèn)題的。
向上轉(zhuǎn)型實(shí)際上是把一個(gè)子類(lèi)型安全地變成了更加抽象的父類(lèi)型,由于所有類(lèi)的根類(lèi)都是Object,我們也把子類(lèi)類(lèi)型轉(zhuǎn)換為Object類(lèi)型:
Cat cat = new Cat();
Object o = cat;
2.4 向下轉(zhuǎn)型
向上轉(zhuǎn)型是父類(lèi)引用指向子類(lèi)實(shí)例,那么如何讓子類(lèi)引用指向父類(lèi)實(shí)例呢?使用向下轉(zhuǎn)型就可以實(shí)現(xiàn)。向下轉(zhuǎn)型也被稱(chēng)為強(qiáng)制類(lèi)型轉(zhuǎn)換。例如:
// 為Cat類(lèi)增加run方法
class Cat extends Pet { // 繼承父類(lèi)
// 重寫(xiě)父類(lèi)方法 eat
public void eat() {
System.out.println("貓貓吃貓糧");
}
public void run() {
System.out.println("貓貓跑步");
}
public static void main(String[] args) {
// 實(shí)例化子類(lèi)
Pet cat = new Cat();
// 強(qiáng)制類(lèi)型轉(zhuǎn)換,只有轉(zhuǎn)換為Cat對(duì)象后,才能調(diào)用其下面的run方法
Cat catObj = (Cat)cat;
catObj.run();
}
}
運(yùn)行結(jié)果:
貓貓跑步
我們?yōu)?code>Cat類(lèi)新增了一個(gè)run方法,此時(shí)我們無(wú)法通過(guò)Pet類(lèi)型的cat實(shí)例調(diào)用到其下面特有的run方法,需要向下轉(zhuǎn)型,通過(guò)(Cat)cat將Pet類(lèi)型的對(duì)象強(qiáng)制轉(zhuǎn)換為Cat類(lèi)型,這個(gè)時(shí)候就可以調(diào)用run方法了。
使用向下轉(zhuǎn)型的時(shí)候,要注意:不能將父類(lèi)對(duì)象轉(zhuǎn)換為子類(lèi)類(lèi)型,也不能將兄弟類(lèi)對(duì)象相互轉(zhuǎn)換。以下兩種都是錯(cuò)誤的做法:
// 實(shí)例化父類(lèi)
Pet pet = new Pet();
// 將父類(lèi)轉(zhuǎn)換為子類(lèi)
Cat cat = (Cat) pet;
// 實(shí)例化Dog類(lèi)
Dog dog = new Dog();
// 兄弟類(lèi)轉(zhuǎn)換
Cat catObj = (Cat) dog;
不能將父類(lèi)轉(zhuǎn)換為子類(lèi),因?yàn)樽宇?lèi)功能比父類(lèi)多,多的功能無(wú)法憑空變出來(lái)。兄弟類(lèi)之間不能轉(zhuǎn)換,這就更容易理解了,兄弟類(lèi)之間同樣功能不盡相同,不同的功能也無(wú)法憑空變出來(lái)。
3. instanceof 運(yùn)算符
instanceof運(yùn)算符用來(lái)檢查對(duì)象引用是否是類(lèi)型的實(shí)例,或者這個(gè)類(lèi)型的子類(lèi),并返回布爾值。如果是返回true,如果不是返回false。通常可以在運(yùn)行時(shí)使用 instanceof 運(yùn)算符指出某個(gè)對(duì)象是否滿(mǎn)足一個(gè)特定類(lèi)型的實(shí)例特征。其使用語(yǔ)法為:
<對(duì)象引用> instanceof 特定類(lèi)型
例如,在向下轉(zhuǎn)型之前,可以使用instanceof運(yùn)算符判斷,這樣可以提高向下轉(zhuǎn)型的安全性:
Pet pet = new Cat();
if (pet instanceof Cat) {
// 將父類(lèi)轉(zhuǎn)換為子類(lèi)
Cat cat = (Cat) pet;
}
4. 小結(jié)
通過(guò)本小節(jié)的學(xué)習(xí),我們知道了多態(tài)意味著一個(gè)對(duì)象有著多重特征,可以在特定的情況下,表現(xiàn)出不同狀態(tài),從而對(duì)應(yīng)著不同的屬性和方法。實(shí)現(xiàn)多態(tài)有 3 個(gè)必要條件,分別是要有繼承、要有重寫(xiě)以及父類(lèi)引用指向子類(lèi)對(duì)象,通過(guò)向上轉(zhuǎn)型可以使父類(lèi)引用指向子類(lèi)實(shí)例;通過(guò)向下轉(zhuǎn)型可以使子類(lèi)引用指向父類(lèi)實(shí)例,使用instanceof運(yùn)算符可以用來(lái)檢查對(duì)象引用是否是類(lèi)型的實(shí)例。
ColorfulC ·
2025 imooc.com All Rights Reserved |