Java多態(tài)中的向上轉(zhuǎn)型與向下轉(zhuǎn)型淺析
向上轉(zhuǎn)型
概念明細(xì)
【原理】:實(shí)際就是創(chuàng)建一個(gè)子類對象,將其當(dāng)成父類對象來使用.
語法格式:父類類型 對象名 = new 子類類型()
Animal animal = new Cat("元寶",2); //animal是父類類型,但可以引用一個(gè)子類對象,因?yàn)槭菑男》秶虼蠓秶霓D(zhuǎn)換
以下是定義的父類Animal類它的兩個(gè)繼承類Cat類和Dog類,分別重寫了Animal類的eat()
方法
class Animal{ String name; int age; public Animal(String name, int age) { this.name = name; this.age = age; } public void eat(){ System.out.println(age + "歲的" + name + "正在吃東西"); } } class Cat extends Animal { public Cat(String name, int age) { super(name, age); } @Override public void eat() { System.out.println(age + "歲的" + name + "正在吃貓糧"); } } class Dog extends Animal { public Dog(String name, int age) { super(name, age); } @Override public void eat() { System.out.println(age + "歲的" + name + "正在吃狗糧"); } }
使用場景1:直接賦值
以下這種就是直接賦值類型的向上轉(zhuǎn)型,將子類對象的引用給到父類對象。然后再將這個(gè)對象作為參數(shù)傳遞進(jìn)去,就可以根據(jù)不同引用調(diào)用不同的行為
public class Test1 { public static void eat(Animal animal) { animal.eat(); } public static void main(String[] args) { Animal animal1 = new Animal("動物",3); Animal animal2 = new Cat("加菲貓",2); Animal animal3 = new Dog("哈士奇",1); eat(animal1); eat(animal2); eat(animal3); } }
使用場景2:
方法傳參 第二種方法傳參很簡單,我們連對象都不需要?jiǎng)?chuàng)建,只需要直接將三種不同對象的引用作為實(shí)參傳遞給到eat()
中的形參接受,就可以產(chǎn)生【向上轉(zhuǎn)型】
public class Test1 { public static void eat(Animal animal) { animal.eat(); } public static void main(String[] args) { eat(new Animal("動物",3)); eat(new Cat("加菲貓",2)); eat(new Dog("哈士奇",1)); } }
使用場景3:
方法返回 第三種便是在一個(gè)方法中將不同對象的引用進(jìn)行返回,然后傳遞給到父類對象,也可以產(chǎn)生向上轉(zhuǎn)型
public static void eat(Animal animal) { animal.eat(); }
稍微講一下這個(gè)方法,可以看到形參是String
字符類型,在方法中通過判斷外界傳入進(jìn)來的字符串然后對應(yīng)地進(jìn)行返回
- 若是“貓”就返Cat對象的引用;
- 若是“狗”就返Dog對象的引用;
- 若是其他就返null
public static Animal BuyAnimal(String var) { if(var.equals("貓")){ return new Cat("加菲貓",2); }else if(var.equals("狗")){ return new Dog("哈士奇",1); }else{ return null; } }
Animal animal1 = BuyAnimal("貓"); eat(animal1); Animal animal2 = BuyAnimal("狗"); eat(animal2); Animal animal3 = BuyAnimal("兔"); eat(animal3);
然后可以看到,前兩個(gè)傳入的是【貓】和【狗】,因此執(zhí)行的便是不同對象的行為,但是在最后傳入了【兔】,因此在BuyAnimal()方法中會return null
這就使得傳入eat()方法中去調(diào)用相關(guān)對象的行為時(shí)因?yàn)椴淮嬖谶@個(gè)對象的引用,所以就會產(chǎn)生空指針異常
上述便是向上轉(zhuǎn)型的三種場景。學(xué)會辨別和使用即可
向上轉(zhuǎn)型的優(yōu)缺點(diǎn)
【優(yōu)點(diǎn)】:讓代碼實(shí)現(xiàn)更簡單靈活,這個(gè)從上面的三個(gè)不同場景就可以看得出來
【缺點(diǎn)】:不能調(diào)用到子類特有的方法??
比如說我在Dog
類中寫了一個(gè)它自己獨(dú)有的方法lookdoor()
class Dog extends Animal { public Dog(String name, int age) { super(name, age); } @Override public void eat() { System.out.println(age + "歲的" + name + "正在吃狗糧"); } public void lookdoor(){ System.out.println(name + "在看門"); } }
但是可以看到,我在通過向上轉(zhuǎn)型之后通過父類對象接受子類引用但是調(diào)用不到子類中特有的方法,這其實(shí)就是向上轉(zhuǎn)型的缺陷
【注意事項(xiàng)】
- 上轉(zhuǎn)型對象不可以訪問子類新增的成員變量和子類自己新增的方法,因?yàn)檫@是子類獨(dú)有的,而父類中沒有
- 上轉(zhuǎn)型對象可以訪問子類繼承的方法或者是子類重寫的方法,這個(gè)時(shí)候當(dāng)上轉(zhuǎn)型對象去調(diào)用這個(gè)方法時(shí),一定是調(diào)用了子類重寫后的方法,這就是我們前面在講繼承的時(shí)候所提到的方法重寫
- 不可以將父類創(chuàng)建的對象的引用賦值給子類聲明的對象,也就是下面的這兩句代碼,這很明顯和我們的上轉(zhuǎn)型對象相反的,我們是將子類對象給到父類的引用,但這是將父類的引用給到子類的對象,完全就是顛倒黑白【就和貓是動物,動物卻不是貓??一個(gè)道理】
向下轉(zhuǎn)型
接下去我們來講講向下轉(zhuǎn)型,這種類型的轉(zhuǎn)化不太安全,如果沒有特殊需求,不建議使用
向下轉(zhuǎn)型解決【調(diào)用子類獨(dú)有方法】
繼續(xù)上面的談到的在向上轉(zhuǎn)型之后無法調(diào)用子類獨(dú)有的方法這個(gè)問題,其實(shí)向下轉(zhuǎn)型就可以解決,代碼如下
Animal animal1 = new Dog("哈士奇",1); animal1.eat(); //animal1.lookdoor(); Dog dog = (Dog) animal1; dog.lookdoor();
可以看到,也就是將父類的對象animal
強(qiáng)轉(zhuǎn)成為Dog狗類
的對象,這樣的話其實(shí)就可以去調(diào)用子類中特有的方法了
向下轉(zhuǎn)型的缺陷
那為什么說向下轉(zhuǎn)型不安全呢,因?yàn)樗嬖诎踩[患
Animal animal1 = new Cat("加菲貓",2); animal1.eat(); //animal1.lookdoor(); Dog dog = (Dog) animal1; dog.lookdoor();
可以看到我將原先的Dog狗類
變?yōu)榱?code>Cat貓類,此時(shí)animal就得到了貓類對象的引用,但是在下面可以看到如果將這個(gè)animal強(qiáng)轉(zhuǎn)為Dog狗類
的對象其實(shí)就會出問題了
看到編譯器報(bào)出了ClassCastException —— 類型轉(zhuǎn)換異常
向下轉(zhuǎn)型的優(yōu)化
??向下轉(zhuǎn)型用的比較少,而且不安全,萬一轉(zhuǎn)換失敗,運(yùn)行時(shí)就會拋異常。
??Java中為了提高向下轉(zhuǎn)型的安全性,引入了 instanceof ,如果該表達(dá)式為true,則可以安全轉(zhuǎn)換
可以看到,在進(jìn)行強(qiáng)轉(zhuǎn)之前我通過instanceof
這個(gè)關(guān)鍵字進(jìn)行了一下判斷,看看animal1是否獲取到了Dog類的引用,若是才可以進(jìn)行強(qiáng)制類型轉(zhuǎn)化,若不是的話就不會進(jìn)行任何操作
Animal animal1 = new Cat("加菲貓",2); animal1.eat(); //animal1.lookdoor(); if(animal1 instanceof Dog){ //判斷一下animal1是否獲取到了Dog類的引用 Dog dog = (Dog) animal1; dog.lookdoor(); }
如果對instance關(guān)鍵字感興趣的可以看看官方的文檔 ——> instanceof關(guān)鍵字
再度對比二者【碎碎念】
可能在上面這一系列說來有點(diǎn)難分辨,我們再來對比看看
其實(shí)你可以這么去想Animal animal1 = new Cat
可以看成是貓歸屬于一個(gè)動物類,那貓一定是屬于動物的
但是看到Dog dog = (Dog) animal1
其實(shí)就要去思考把動物歸屬于狗,這其實(shí)是說不通的,難道只要是動物就一定是狗嗎?那可不一定,動物可多的是
總結(jié)與提煉
來總結(jié)一下本文所學(xué)到的內(nèi)容
- 在本文中我們講到了多態(tài)中的【向上轉(zhuǎn)型】與【向下轉(zhuǎn)型】
- 首先是說到了向上轉(zhuǎn)型,介紹了它會出現(xiàn)的三種場景,也分析了它的優(yōu)缺點(diǎn),知道了在向下轉(zhuǎn)型之后無法調(diào)用子類特有的方法
- 但是在向下轉(zhuǎn)型中,我們解決了這個(gè)問題,通過對父類對象進(jìn)行一個(gè)強(qiáng)轉(zhuǎn),就可以調(diào)用到子類當(dāng)中的方法,不過可以看到這種做法不太安全,若是一開始父類對象接受了一個(gè)子類的引用,但是在強(qiáng)轉(zhuǎn)的時(shí)候轉(zhuǎn)化為了另外一個(gè)子類,就會造成類型轉(zhuǎn)換的問題
- 于是后面對方法進(jìn)行了修正,在前面加上了instanceof關(guān)鍵字進(jìn)行一個(gè)判斷,只有父類接收到了這個(gè)子類的引用,才可以強(qiáng)轉(zhuǎn)為這個(gè)子類的對象
到此這篇關(guān)于Java多態(tài)中的向上轉(zhuǎn)型與向下轉(zhuǎn)型的文章就介紹到這了,更多相關(guān)Java多態(tài)向上轉(zhuǎn)型與向下轉(zhuǎn)型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談Spring Cloud Eureka 自我保護(hù)機(jī)制
這篇文章主要介紹了淺談Spring Cloud Eureka 自我保護(hù)機(jī)制,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-06-06Spring cloud 查詢返回廣告創(chuàng)意實(shí)例代碼
在本篇文章里小編給大家整理的是關(guān)于Spring cloud 查詢返回廣告創(chuàng)意實(shí)例代碼,需要的朋友們可以跟著學(xué)習(xí)下。2019-08-08