學(xué)習(xí)Java之如何正確地向上轉(zhuǎn)型與向下轉(zhuǎn)型
一. 類型轉(zhuǎn)型
將一個(gè)類型轉(zhuǎn)換成另一個(gè)類型的過程被稱為類型轉(zhuǎn)換。 我們所說的對(duì)象類型轉(zhuǎn)換,一般是指兩個(gè)存在繼承關(guān)系的對(duì)象,而不是任意類型的對(duì)象。如果兩個(gè)類型之間沒有繼承關(guān)系,就不允許進(jìn)行類型轉(zhuǎn)換,否則會(huì)拋出強(qiáng)制類型轉(zhuǎn)換異常(java.lang.ClassCastException)。
Java語言允許某個(gè)類型的引用變量引用子類的實(shí)例,而且可以對(duì)這個(gè)引用變量進(jìn)行類型轉(zhuǎn)換。Java中引用類型之間的類型轉(zhuǎn)換(前提是兩個(gè)類是直接或間接的父子關(guān)系)主要有兩種,分別是向上轉(zhuǎn)型(upcasting)和向下轉(zhuǎn)型(downcasting) 。
我們先來看下面這張圖:

貓、狗、牛、羊都是動(dòng)物,所以”動(dòng)物“是父類,貓狗牛羊是具體的子類。我們可以說貓是動(dòng)物,狗是動(dòng)物,牛是動(dòng)物,羊是動(dòng)物,這個(gè)結(jié)論肯定沒錯(cuò)!但如果我們說,動(dòng)物是貓,動(dòng)物是狗,動(dòng)物是牛,動(dòng)物是羊,這個(gè)結(jié)論一定正確嗎?那可就不一定了。子類肯定符合父類類型,但反之,父類不一定符合子類類型!
接下來分別對(duì)向上轉(zhuǎn)型和向下轉(zhuǎn)型進(jìn)行講解。
二. 向上轉(zhuǎn)型
1. 概念
所謂的向上轉(zhuǎn)型,就是父類引用指向子類的對(duì)象,也就是把子類對(duì)象直接賦給父類引用變量,此時(shí)不用強(qiáng)制轉(zhuǎn)換。比如我們說貓是動(dòng)物,狗是動(dòng)物,牛是動(dòng)物,羊是動(dòng)物,這就是把子類當(dāng)成父類來用。父類是子類的上級(jí),我們直接把子類向上提拔轉(zhuǎn)型了。
2. 特點(diǎn)
向上轉(zhuǎn)型具有如下特點(diǎn):
- 編譯類型取決于=號(hào)左邊,運(yùn)行類型取決于=號(hào)右邊;
- 子類可以調(diào)用父類的所有成員,但需遵守訪問權(quán)限;
- 父類不能調(diào)用子類的特有成員;
- 最終的運(yùn)行效果取決于子類的具體實(shí)現(xiàn)。
3. 語法
向上轉(zhuǎn)型的基本語法如下所示:
//左側(cè)是父類引用變量,右側(cè)是創(chuàng)建的子類對(duì)象,我們可以把它當(dāng)作父類使用 父類類型 引用名 = new 子類類型();
4. 案例
接下來我們通過一個(gè)案例來演示向上轉(zhuǎn)型該如何實(shí)現(xiàn)。
/**
* @author 一一哥Sun
* 定義父類---向上與向下轉(zhuǎn)型
*/
public interface Animal {
//叫
public void speak();
}
//Dog類實(shí)現(xiàn)Animal接口
public class Dog implements Animal {
@Override
public void speak() {
System.out.println("狗子:汪汪");
}
}
//Cat類實(shí)現(xiàn)Animal接口
public class Cat implements Animal {
@Override
public void speak() {
System.out.println("貓子:喵喵");
}
}
//定義一個(gè)測(cè)試類
public class AnimalTest {
public static void main(String[] args) {
//向上轉(zhuǎn)型
//父類引用dog變量,指向子類對(duì)象new Dog();
//動(dòng)物 = 狗;以下代碼的意思就是”狗是動(dòng)物“
Animal dog=new Dog();
//向上轉(zhuǎn)型后,可以使用父類Animal中的屬性和方法。
dog.speak();
//Animal animal=new Cat();效果等同于如下兩行代碼:
Cat cat=new Cat();
Animal animal=cat;
animal.speak();
}
}我們?cè)谶M(jìn)行向上轉(zhuǎn)型時(shí),可以寫成Animal animal=new Cat(); Animal animal=cat;的形式。就是先創(chuàng)建出cat對(duì)象,然后再將cat對(duì)象賦值給Animal類型的變量,這樣就實(shí)現(xiàn)了向上轉(zhuǎn)型。因?yàn)锳nimal是父級(jí)類型,Cat是子級(jí)類型,Cat是Animal的子類,所以可以直接將cat變量賦值給animal,這就是向上轉(zhuǎn)型。但這種寫法比較繁瑣,我們通常是直接采用Animal cat=new Cat();的形式,簡(jiǎn)潔明了。
我們之所以可以實(shí)現(xiàn)向上轉(zhuǎn)型,主要是因?yàn)閮蓚€(gè)類型之間是父子關(guān)系。比如在本例中,向上轉(zhuǎn)型就等于說”貓是動(dòng)物,狗是動(dòng)物“,因?yàn)樨埞范际莿?dòng)物的子類,所以這個(gè)結(jié)論是確定無誤的。
三. 向下轉(zhuǎn)型
1. 概念
向下轉(zhuǎn)型則反之,也就是一個(gè)已經(jīng)向上轉(zhuǎn)型的子類對(duì)象指向父類引用。 向下轉(zhuǎn)型后,可以調(diào)用子類類型中所有的成員。向下轉(zhuǎn)型時(shí),必須進(jìn)行強(qiáng)制類型轉(zhuǎn)換。因?yàn)?strong>父類擁有的成員,子類肯定會(huì)有,但子類擁有的成員,父類不一定有。
但要注意,如果父類的引用對(duì)象指向的是子類對(duì)象,則向下轉(zhuǎn)型時(shí)是安全的,即編譯時(shí)不會(huì)出現(xiàn)錯(cuò)誤。但如果父類的引用對(duì)象是父類本身,那么在向下轉(zhuǎn)型的過程中是不安全的,雖然編譯時(shí)不會(huì)出錯(cuò),但在運(yùn)行過程中會(huì)出現(xiàn)強(qiáng)制類型轉(zhuǎn)換異常。我們可以使用instanceof運(yùn)算符來避免出現(xiàn)強(qiáng)制類型轉(zhuǎn)換異常。
2. 特點(diǎn)
向下轉(zhuǎn)型具有如下特點(diǎn):
- 只能強(qiáng)制轉(zhuǎn)換父類的引用,不能強(qiáng)制轉(zhuǎn)換父類的對(duì)象;
- 父類的引用必須指向子類目標(biāo)類型的對(duì)象;
- 向下轉(zhuǎn)型后,父類可以調(diào)用子類類型中的所有成員。
3. 語法
向下轉(zhuǎn)型的基本語法如下所示:
//向下轉(zhuǎn)型使用強(qiáng)制類型轉(zhuǎn)換的格式,將父類引用類型轉(zhuǎn)換為子類引用類型 子類類型 引用名 = (子類類型) 父類引用;
4. 案例
接下來我們?cè)谏厦娴陌咐A(chǔ)之上,對(duì)代碼進(jìn)行改造,在Cat類中增加一個(gè)新的方法。
public class Cat implements Animal {
@Override
public void speak() {
System.out.println("貓子:喵喵");
}
//給其他動(dòng)物打招呼
public void helloAnimal(Animal animal) {
//向下轉(zhuǎn)型,將父類型轉(zhuǎn)為子類型。
//此時(shí)有可能會(huì)出現(xiàn)ClassCastException類型轉(zhuǎn)換異常,因?yàn)樽宇愐欢▽儆诟割惖囊粏T,但父類不一定屬于子類。
//我們說“貓是動(dòng)物”一定沒問題,但如果說“動(dòng)物是貓”,這個(gè)結(jié)論未必正確。所以把“動(dòng)物強(qiáng)轉(zhuǎn)成貓”的過程中,有可能會(huì)出現(xiàn)異常。
//只有兩者之間具有明確的父子關(guān)系時(shí)才能進(jìn)行強(qiáng)轉(zhuǎn),否則就會(huì)出現(xiàn)類型轉(zhuǎn)換異常。
//向下轉(zhuǎn)型時(shí)需要進(jìn)行類型強(qiáng)轉(zhuǎn)
Cat cat=(Cat) animal;
//向下轉(zhuǎn)型后,可以使用子類Cat中的屬性和方法。
cat.speak();
}
}
//測(cè)試類
public class AnimalTest {
public static void main(String[] args) {
Animal animal=new Cat();
animal.speak();
Cat cat=new Cat();
//這里我們傳參時(shí),既可以傳遞animal,也可以傳遞cat,但不能傳遞dog類型,否則會(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ì)象類型轉(zhuǎn)換成Cat對(duì)象類型
//Cat cat = (Cat)dog;
}
}向下轉(zhuǎn)型就是將父類型轉(zhuǎn)為子類型,但要注意,此時(shí)有可能會(huì)出現(xiàn)ClassCastException類型轉(zhuǎn)換異常,因?yàn)樽宇愐欢▽儆诟割惖囊粏T,但父類不一定屬于子類。我們說“貓是動(dòng)物”一定沒問題,但如果說“動(dòng)物是貓”,這個(gè)結(jié)論未必正確。所以把“動(dòng)物強(qiáng)轉(zhuǎn)成貓”的過程中,有可能會(huì)出現(xiàn)異常。只有兩者之間具有明確的父子關(guān)系時(shí)才能進(jìn)行強(qiáng)轉(zhuǎn),否則就會(huì)出現(xiàn)類型轉(zhuǎn)換異常。
就比如上面的案例中,我們傳參時(shí),既可以傳遞animal,也可以傳遞cat,但不能傳遞dog類型,否則會(huì)出現(xiàn)java.lang.ClassCastException,因?yàn)閏lass com.yyg.convert.Dog cannot be cast to class com.yyg.convert.Cat,狗類不能被轉(zhuǎn)成貓類。
四. 結(jié)語
至此,就把類型轉(zhuǎn)換給大家介紹完了,我們來看看類型轉(zhuǎn)換的要點(diǎn)吧::
- 向上轉(zhuǎn)型是父類引用指向子類的對(duì)象,不必強(qiáng)制類型轉(zhuǎn)換 ;
- 向下轉(zhuǎn)型是子類對(duì)象指向父類引用,必須進(jìn)行強(qiáng)制類型轉(zhuǎn)換;
- 可以強(qiáng)制向下轉(zhuǎn)型最好借助instanceOf進(jìn)行類型判斷;
以上就是學(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)文章
MyBatis-Plus自動(dòng)化填充的踩坑記錄及解決
這篇文章主要介紹了MyBatis-Plus自動(dòng)化填充的踩坑記錄及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
解決fastjson從1.1.41升級(jí)到1.2.28后報(bào)錯(cuò)問題詳解
這篇文章主要介紹了解決fastjson從1.1.41升級(jí)到1.2.28后報(bào)錯(cuò)問題詳解,需要的朋友可以參考下2020-02-02
Java倒計(jì)時(shí)三種實(shí)現(xiàn)方式代碼實(shí)例
這篇文章主要介紹了Java倒計(jì)時(shí)三種實(shí)現(xiàn)方式代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
java 字符串轉(zhuǎn)化為字符數(shù)組的3種實(shí)現(xiàn)案例
這篇文章主要介紹了java 字符串轉(zhuǎn)化為字符數(shù)組的3種實(shí)現(xiàn)案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-10-10
Java用數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列的示例
下面小編就為大家?guī)硪黄狫ava用數(shù)組實(shí)現(xiàn)循環(huán)隊(duì)列的示例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09
JavaWeb簡(jiǎn)單用戶登錄注冊(cè)實(shí)例代碼(有驗(yàn)證碼)
這篇文章主要介紹了JavaWeb簡(jiǎn)單用戶登錄注冊(cè)實(shí)例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
Spring Security獲取用戶認(rèn)證信息的實(shí)現(xiàn)流程
Spring Security是一個(gè)能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應(yīng)用上下文中配置的Bean,充分利用了Spring IoC,DI和AOP功能,為應(yīng)用系統(tǒng)提供聲明式的安全訪問控制功能2022-12-12
詳解SpringBoot2 使用Spring Session集群
這篇文章主要介紹了SpringBoot2 使用Spring Session集群,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下2019-04-04
Spring應(yīng)用中使用acutator/refresh刷新屬性不生效的問題分析及解決
在Spring應(yīng)用收到/actuator/refresh的POST請(qǐng)求后,標(biāo)注了@RefreshScope以及@ConfiguratioinProperties的bean會(huì)被Spring容器重新加載,但是,在實(shí)際應(yīng)用中,并沒有按照預(yù)期被Spring容器加載,本文將討論導(dǎo)致這種未按預(yù)期刷新的一種原因,感興趣的朋友可以參考下2024-01-01

