學(xué)習(xí)Java之如何正確地向上轉(zhuǎn)型與向下轉(zhuǎn)型
一. 類(lèi)型轉(zhuǎn)型
將一個(gè)類(lèi)型轉(zhuǎn)換成另一個(gè)類(lèi)型的過(guò)程被稱(chēng)為類(lèi)型轉(zhuǎn)換。 我們所說(shuō)的對(duì)象類(lèi)型轉(zhuǎn)換,一般是指兩個(gè)存在繼承關(guān)系的對(duì)象,而不是任意類(lèi)型的對(duì)象。如果兩個(gè)類(lèi)型之間沒(méi)有繼承關(guān)系,就不允許進(jìn)行類(lèi)型轉(zhuǎn)換,否則會(huì)拋出強(qiáng)制類(lèi)型轉(zhuǎn)換異常(java.lang.ClassCastException)。
Java語(yǔ)言允許某個(gè)類(lèi)型的引用變量引用子類(lèi)的實(shí)例,而且可以對(duì)這個(gè)引用變量進(jìn)行類(lèi)型轉(zhuǎn)換。Java中引用類(lèi)型之間的類(lèi)型轉(zhuǎn)換(前提是兩個(gè)類(lèi)是直接或間接的父子關(guān)系)主要有兩種,分別是向上轉(zhuǎn)型(upcasting)和向下轉(zhuǎn)型(downcasting) 。
我們先來(lái)看下面這張圖:
貓、狗、牛、羊都是動(dòng)物,所以”動(dòng)物“是父類(lèi),貓狗牛羊是具體的子類(lèi)。我們可以說(shuō)貓是動(dòng)物,狗是動(dòng)物,牛是動(dòng)物,羊是動(dòng)物,這個(gè)結(jié)論肯定沒(méi)錯(cuò)!但如果我們說(shuō),動(dòng)物是貓,動(dòng)物是狗,動(dòng)物是牛,動(dòng)物是羊,這個(gè)結(jié)論一定正確嗎?那可就不一定了。子類(lèi)肯定符合父類(lèi)類(lèi)型,但反之,父類(lèi)不一定符合子類(lèi)類(lèi)型!
接下來(lái)分別對(duì)向上轉(zhuǎn)型和向下轉(zhuǎn)型進(jìn)行講解。
二. 向上轉(zhuǎn)型
1. 概念
所謂的向上轉(zhuǎn)型,就是父類(lèi)引用指向子類(lèi)的對(duì)象,也就是把子類(lèi)對(duì)象直接賦給父類(lèi)引用變量,此時(shí)不用強(qiáng)制轉(zhuǎn)換。比如我們說(shuō)貓是動(dòng)物,狗是動(dòng)物,牛是動(dòng)物,羊是動(dòng)物,這就是把子類(lèi)當(dāng)成父類(lèi)來(lái)用。父類(lèi)是子類(lèi)的上級(jí),我們直接把子類(lèi)向上提拔轉(zhuǎn)型了。
2. 特點(diǎn)
向上轉(zhuǎn)型具有如下特點(diǎn):
- 編譯類(lèi)型取決于=號(hào)左邊,運(yùn)行類(lèi)型取決于=號(hào)右邊;
- 子類(lèi)可以調(diào)用父類(lèi)的所有成員,但需遵守訪問(wèn)權(quán)限;
- 父類(lèi)不能調(diào)用子類(lèi)的特有成員;
- 最終的運(yùn)行效果取決于子類(lèi)的具體實(shí)現(xiàn)。
3. 語(yǔ)法
向上轉(zhuǎn)型的基本語(yǔ)法如下所示:
//左側(cè)是父類(lèi)引用變量,右側(cè)是創(chuàng)建的子類(lèi)對(duì)象,我們可以把它當(dāng)作父類(lèi)使用 父類(lèi)類(lèi)型 引用名 = new 子類(lèi)類(lèi)型();
4. 案例
接下來(lái)我們通過(guò)一個(gè)案例來(lái)演示向上轉(zhuǎn)型該如何實(shí)現(xiàn)。
/** * @author 一一哥Sun * 定義父類(lèi)---向上與向下轉(zhuǎn)型 */ public interface Animal { //叫 public void speak(); } //Dog類(lèi)實(shí)現(xiàn)Animal接口 public class Dog implements Animal { @Override public void speak() { System.out.println("狗子:汪汪"); } } //Cat類(lèi)實(shí)現(xiàn)Animal接口 public class Cat implements Animal { @Override public void speak() { System.out.println("貓子:喵喵"); } } //定義一個(gè)測(cè)試類(lèi) public class AnimalTest { public static void main(String[] args) { //向上轉(zhuǎn)型 //父類(lèi)引用dog變量,指向子類(lèi)對(duì)象new Dog(); //動(dòng)物 = 狗;以下代碼的意思就是”狗是動(dòng)物“ Animal dog=new Dog(); //向上轉(zhuǎn)型后,可以使用父類(lèi)Animal中的屬性和方法。 dog.speak(); //Animal animal=new Cat();效果等同于如下兩行代碼: Cat cat=new Cat(); Animal animal=cat; animal.speak(); } }
我們?cè)谶M(jìn)行向上轉(zhuǎn)型時(shí),可以寫(xiě)成Animal animal=new Cat(); Animal animal=cat;
的形式。就是先創(chuàng)建出cat對(duì)象,然后再將cat對(duì)象賦值給Animal類(lèi)型的變量,這樣就實(shí)現(xiàn)了向上轉(zhuǎn)型。因?yàn)锳nimal是父級(jí)類(lèi)型,Cat是子級(jí)類(lèi)型,Cat是Animal的子類(lèi),所以可以直接將cat變量賦值給animal,這就是向上轉(zhuǎn)型。但這種寫(xiě)法比較繁瑣,我們通常是直接采用Animal cat=new Cat();
的形式,簡(jiǎn)潔明了。
我們之所以可以實(shí)現(xiàn)向上轉(zhuǎn)型,主要是因?yàn)閮蓚€(gè)類(lèi)型之間是父子關(guān)系。比如在本例中,向上轉(zhuǎn)型就等于說(shuō)”貓是動(dòng)物,狗是動(dòng)物“,因?yàn)樨埞范际莿?dòng)物的子類(lèi),所以這個(gè)結(jié)論是確定無(wú)誤的。
三. 向下轉(zhuǎn)型
1. 概念
向下轉(zhuǎn)型則反之,也就是一個(gè)已經(jīng)向上轉(zhuǎn)型的子類(lèi)對(duì)象指向父類(lèi)引用。 向下轉(zhuǎn)型后,可以調(diào)用子類(lèi)類(lèi)型中所有的成員。向下轉(zhuǎn)型時(shí),必須進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換。因?yàn)?strong>父類(lèi)擁有的成員,子類(lèi)肯定會(huì)有,但子類(lèi)擁有的成員,父類(lèi)不一定有。
但要注意,如果父類(lèi)的引用對(duì)象指向的是子類(lèi)對(duì)象,則向下轉(zhuǎn)型時(shí)是安全的,即編譯時(shí)不會(huì)出現(xiàn)錯(cuò)誤。但如果父類(lèi)的引用對(duì)象是父類(lèi)本身,那么在向下轉(zhuǎn)型的過(guò)程中是不安全的,雖然編譯時(shí)不會(huì)出錯(cuò),但在運(yùn)行過(guò)程中會(huì)出現(xiàn)強(qiáng)制類(lèi)型轉(zhuǎn)換異常。我們可以使用instanceof運(yùn)算符來(lái)避免出現(xiàn)強(qiáng)制類(lèi)型轉(zhuǎn)換異常。
2. 特點(diǎn)
向下轉(zhuǎn)型具有如下特點(diǎn):
- 只能強(qiáng)制轉(zhuǎn)換父類(lèi)的引用,不能強(qiáng)制轉(zhuǎn)換父類(lèi)的對(duì)象;
- 父類(lèi)的引用必須指向子類(lèi)目標(biāo)類(lèi)型的對(duì)象;
- 向下轉(zhuǎn)型后,父類(lèi)可以調(diào)用子類(lèi)類(lèi)型中的所有成員。
3. 語(yǔ)法
向下轉(zhuǎn)型的基本語(yǔ)法如下所示:
//向下轉(zhuǎn)型使用強(qiáng)制類(lèi)型轉(zhuǎn)換的格式,將父類(lèi)引用類(lèi)型轉(zhuǎn)換為子類(lèi)引用類(lèi)型 子類(lèi)類(lèi)型 引用名 = (子類(lèi)類(lèi)型) 父類(lèi)引用;
4. 案例
接下來(lái)我們?cè)谏厦娴陌咐A(chǔ)之上,對(duì)代碼進(jìn)行改造,在Cat類(lèi)中增加一個(gè)新的方法。
public class Cat implements Animal { @Override public void speak() { System.out.println("貓子:喵喵"); } //給其他動(dòng)物打招呼 public void helloAnimal(Animal animal) { //向下轉(zhuǎn)型,將父類(lèi)型轉(zhuǎn)為子類(lèi)型。 //此時(shí)有可能會(huì)出現(xiàn)ClassCastException類(lèi)型轉(zhuǎn)換異常,因?yàn)樽宇?lèi)一定屬于父類(lèi)的一員,但父類(lèi)不一定屬于子類(lèi)。 //我們說(shuō)“貓是動(dòng)物”一定沒(méi)問(wèn)題,但如果說(shuō)“動(dòng)物是貓”,這個(gè)結(jié)論未必正確。所以把“動(dòng)物強(qiáng)轉(zhuǎn)成貓”的過(guò)程中,有可能會(huì)出現(xiàn)異常。 //只有兩者之間具有明確的父子關(guān)系時(shí)才能進(jìn)行強(qiáng)轉(zhuǎn),否則就會(huì)出現(xiàn)類(lèi)型轉(zhuǎn)換異常。 //向下轉(zhuǎn)型時(shí)需要進(jìn)行類(lèi)型強(qiáng)轉(zhuǎn) Cat cat=(Cat) animal; //向下轉(zhuǎn)型后,可以使用子類(lèi)Cat中的屬性和方法。 cat.speak(); } } //測(cè)試類(lèi) public class AnimalTest { public static void main(String[] args) { Animal animal=new Cat(); animal.speak(); Cat cat=new Cat(); //這里我們傳參時(shí),既可以傳遞animal,也可以傳遞cat,但不能傳遞dog類(lèi)型,否則會(huì)出現(xiàn)java.lang.ClassCastException: //因?yàn)閏lass com.yyg.convert.Dog cannot be cast to class com.yyg.convert.Cat。狗不能被轉(zhuǎn)成貓 //cat2.helloAnimal(dog); cat.helloAnimal(animal); //Dog dog = new Dog(); //這里就會(huì)編譯出錯(cuò),不允許把Dog對(duì)象類(lèi)型轉(zhuǎn)換成Cat對(duì)象類(lèi)型 //Cat cat = (Cat)dog; } }
向下轉(zhuǎn)型就是將父類(lèi)型轉(zhuǎn)為子類(lèi)型,但要注意,此時(shí)有可能會(huì)出現(xiàn)ClassCastException類(lèi)型轉(zhuǎn)換異常,因?yàn)樽宇?lèi)一定屬于父類(lèi)的一員,但父類(lèi)不一定屬于子類(lèi)。我們說(shuō)“貓是動(dòng)物”一定沒(méi)問(wèn)題,但如果說(shuō)“動(dòng)物是貓”,這個(gè)結(jié)論未必正確。所以把“動(dòng)物強(qiáng)轉(zhuǎn)成貓”的過(guò)程中,有可能會(huì)出現(xiàn)異常。只有兩者之間具有明確的父子關(guān)系時(shí)才能進(jìn)行強(qiáng)轉(zhuǎn),否則就會(huì)出現(xiàn)類(lèi)型轉(zhuǎn)換異常。
就比如上面的案例中,我們傳參時(shí),既可以傳遞animal,也可以傳遞cat,但不能傳遞dog類(lèi)型,否則會(huì)出現(xiàn)java.lang.ClassCastException,因?yàn)閏lass com.yyg.convert.Dog cannot be cast to class com.yyg.convert.Cat,狗類(lèi)不能被轉(zhuǎn)成貓類(lèi)。
四. 結(jié)語(yǔ)
至此,就把類(lèi)型轉(zhuǎn)換給大家介紹完了,我們來(lái)看看類(lèi)型轉(zhuǎn)換的要點(diǎn)吧::
- 向上轉(zhuǎn)型是父類(lèi)引用指向子類(lèi)的對(duì)象,不必強(qiáng)制類(lèi)型轉(zhuǎn)換 ;
- 向下轉(zhuǎn)型是子類(lèi)對(duì)象指向父類(lèi)引用,必須進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換;
- 可以強(qiáng)制向下轉(zhuǎn)型最好借助instanceOf進(jìn)行類(lèi)型判斷;
以上就是學(xué)習(xí)Java之如何正確地向上轉(zhuǎn)型與向下轉(zhuǎn)型的詳細(xì)內(nèi)容,更多關(guān)于Java向上轉(zhuǎn)型與向下轉(zhuǎn)型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JAVA中的延遲隊(duì)列DelayQueue應(yīng)用解析
這篇文章主要介紹了JAVA中的延遲隊(duì)列DelayQueue應(yīng)用解析,DelayQueue是一個(gè)根據(jù)元素的到期時(shí)間來(lái)排序的隊(duì)列,而并非是一般的隊(duì)列那樣先進(jìn)先出,最快過(guò)期的元素排在隊(duì)首,越晚到期的元素排得越后,需要的朋友可以參考下2023-12-12spring利用squertz實(shí)現(xiàn)定時(shí)任務(wù)
spring squertz是一個(gè)強(qiáng)大的定時(shí)任務(wù)處理方式。下面這篇文章主要介紹了spring利用squertz實(shí)現(xiàn)定時(shí)任務(wù)的相關(guān)資料,文中介紹的很詳細(xì),對(duì)大家具有一定的參考借鑒價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-01-01Java中的權(quán)重算法(如Dubbo的負(fù)載均衡權(quán)重)詳解
這篇文章主要介紹了Java中的權(quán)重算法(如Dubbo的負(fù)載均衡權(quán)重)詳解,負(fù)載均衡,其含義就是指將負(fù)載進(jìn)行平衡、分?jǐn)偟蕉鄠€(gè)操作單元上進(jìn)行運(yùn)行,例如FTP服務(wù)器、Web服務(wù)器、企業(yè)核心應(yīng)用服務(wù)器和其它主要任務(wù)服務(wù)器等,從而協(xié)同完成工作任務(wù),需要的朋友可以參考下2023-08-08如何利用NetworkInterface獲取服務(wù)器MAC地址
今天介紹一種通用的跨平臺(tái)的操作方式,那就是JDK自帶的NetworkInterface接口,該接口在JDK1.4已經(jīng)出現(xiàn),但是功能比較少,JDK1.6之后新增了不少新功能,比較不錯(cuò)2013-08-08springboot不同環(huán)境使用不同配置文件打包方式
這篇文章主要介紹了springboot不同環(huán)境使用不同配置文件打包方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11Spring?MVC中@Controller和@RequestMapping注解使用
這篇文章主要介紹了Spring?MVC中@Controller和@RequestMapping注解使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02Spring Boot 2.X整合Spring-cache(讓你的網(wǎng)站速度飛起來(lái))
這篇文章主要介紹了Spring Boot 2.X整合Spring-cache(讓你的網(wǎng)站速度飛起來(lái)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09