更新時(shí)間:2021-08-11 來(lái)源:黑馬程序員 瀏覽量:
在多態(tài)的學(xué)習(xí)中,涉及到將子類(lèi)對(duì)象當(dāng)做父類(lèi)類(lèi)型使用的情況,此種情況在Java的語(yǔ)言環(huán)境中稱(chēng)為“向上轉(zhuǎn)型”,例如下面兩行代碼:
Animal an1 = new Cat(); // 將Cat類(lèi)對(duì)象當(dāng)做Animal類(lèi)型來(lái)使用 Animal an2 = new Dog(); // 將Dog類(lèi)對(duì)象當(dāng)做Animal類(lèi)型來(lái)使用將子類(lèi)對(duì)象當(dāng)做父類(lèi)使用時(shí)不需要任何顯式地聲明,需要注意的是,此時(shí)不能通過(guò)父類(lèi)變量去調(diào)用子類(lèi)特有的方法。
接下來(lái)通過(guò)一個(gè)案例來(lái)演示對(duì)象的類(lèi)型轉(zhuǎn)換情況,如文件1所示。
文件1 Example16.java
// 定義接口Animal interface Animal { void shout(); // 定義抽象shout()方法 } // 定義Cat類(lèi)實(shí)現(xiàn)Animal接口 class Cat implements Animal { // 實(shí)現(xiàn)接口shout()方法 public void shout() { System.out.println("喵喵……"); } // 定義Cat類(lèi)特有的抓老鼠catchMouse()方法 public void catchMouse() { System.out.println("小貓抓老鼠……"); } } // 定義測(cè)試類(lèi) public class Example16 { public static void main(String[] args) { Animal an1 = new Cat(); an1.shout(); an1.catchMouse(); } }
程序編譯報(bào)錯(cuò),如圖1所示。
圖1 運(yùn)行結(jié)果
從圖1可以看出,程序編譯出現(xiàn)了“The method catchMouse() is undefined for the type Anima(在父類(lèi)Animal中未定義catchMouse()方法)”的錯(cuò)誤。原因在于,創(chuàng)建Cat對(duì)象時(shí)指向了Animal父類(lèi)類(lèi)型,這樣新創(chuàng)建的Cat對(duì)象會(huì)自動(dòng)向上轉(zhuǎn)型為Animal類(lèi),然后通過(guò)父類(lèi)對(duì)象an1分別調(diào)用了shout()方法和子類(lèi)Cat特有的catchMouse()方法,而catchMouse()方法是Cat類(lèi)特有的,所以通過(guò)父類(lèi)對(duì)象調(diào)用時(shí),在編譯期間就會(huì)報(bào)錯(cuò)。
文件1中,由于通過(guò)“new Cat();”創(chuàng)建的對(duì)象本質(zhì)就是Cat類(lèi)型,所以通過(guò)Cat類(lèi)型的對(duì)象調(diào)用catchMouse()方法是可行的,因此要解決上面的問(wèn)題,可以將父類(lèi)類(lèi)型的對(duì)象an1強(qiáng)轉(zhuǎn)為Cat類(lèi)型。接下來(lái)對(duì)文件1中的main()方法進(jìn)行修改,具體代碼如下:
// 定義測(cè)試類(lèi) public class Example16 { public static void main(String[] args) { Animal an1 = new Cat(); Cat cat = (Cat) an1; cat.shout(); cat.catchMouse(); } }
修改后再次編譯,程序沒(méi)有報(bào)錯(cuò),運(yùn)行結(jié)果如圖2所示。
圖2 運(yùn)行結(jié)果
從圖2可以看出,將本質(zhì)為Cat類(lèi)型的an1對(duì)象由Animal類(lèi)型向下轉(zhuǎn)型為Cat類(lèi)型后,程序可以成功運(yùn)行。需要注意的是,在進(jìn)行對(duì)象向下類(lèi)型轉(zhuǎn)換時(shí),必須轉(zhuǎn)換為本質(zhì)類(lèi)型,否則轉(zhuǎn)換時(shí)會(huì)出現(xiàn)錯(cuò)誤,假如文件4-16中Animal類(lèi)型引用指向的是一個(gè)Dog類(lèi)型對(duì)象,這時(shí)進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換為Cat類(lèi)時(shí)就會(huì)出現(xiàn)出錯(cuò),如文件2所示。
文件2 Example17.java
// 定義接口Animal interface Animal { void shout(); // 定義抽象shout()方法 } // 定義Cat類(lèi)實(shí)現(xiàn)Animal接口 class Cat implements Animal { // 實(shí)現(xiàn)接口shout()方法 public void shout() { System.out.println("喵喵……"); } // 定義Cat類(lèi)特有的抓老鼠catchMouse()方法 public void catchMouse() { System.out.println("小貓抓老鼠……"); } } // 定義Dog類(lèi)實(shí)現(xiàn)Animal接口 class Dog implements Animal { // 實(shí)現(xiàn)接口shout()方法 public void shout() { System.out.println("汪汪……"); } } // 定義測(cè)試類(lèi) public class Example17 { public static void main(String[] args) { Animal an1 = new Dog(); Cat cat = (Cat) an1; cat.shout(); cat.catchMouse(); } }
運(yùn)行結(jié)果如圖3所示。
圖3 運(yùn)行結(jié)果
文件2編譯正常,但在運(yùn)行時(shí)就會(huì)報(bào)錯(cuò),提示Dog類(lèi)型不能轉(zhuǎn)換成Cat類(lèi)型。出錯(cuò)的原因是,創(chuàng)建的Animal對(duì)象本質(zhì)是一個(gè)Dog對(duì)象,在強(qiáng)制類(lèi)型轉(zhuǎn)換時(shí),Dog類(lèi)型的對(duì)象顯然無(wú)法強(qiáng)轉(zhuǎn)為Cat類(lèi)型。
為了避免上述這種異常情況的發(fā)生,Java提供了一個(gè)關(guān)鍵字instanceof,它可以判斷一個(gè)對(duì)象是否為某個(gè)類(lèi)(或接口)的實(shí)例或者子類(lèi)實(shí)例,語(yǔ)法格式如下:
對(duì)象(或者對(duì)象引用變量) instanceof 類(lèi)(或接口)
接下來(lái)對(duì)文件2的測(cè)試類(lèi)Example17進(jìn)行修改,具體代碼如下:
// 定義測(cè)試類(lèi)public class Example17 { public static void main(String[] args) { Animal an1 = new Dog(); if(an1 instanceof Cat){ // 判斷an1本質(zhì)類(lèi)型 Cat cat = (Cat) an1; cat.shout(); cat.catchMouse(); }else{ System.out.println("該類(lèi)型的對(duì)象不是Cat類(lèi)型!"); } } }
再次運(yùn)行程序,結(jié)果如圖4所示。
圖4 運(yùn)行結(jié)果
在對(duì)文件2修改的代碼中,使用instanceof關(guān)鍵字判斷對(duì)象an1本質(zhì)是否為Cat類(lèi)型,如果是Cat類(lèi)型就強(qiáng)制轉(zhuǎn)換為Cat類(lèi)型,否則就打印“該類(lèi)型的對(duì)象不是Cat類(lèi)型!”。由于判斷的對(duì)象an1本質(zhì)為Dog類(lèi)型并非Cat類(lèi)型,因此出現(xiàn)圖4的運(yùn)行結(jié)果。
Java中父類(lèi)方法重寫(xiě)有哪些注意事項(xiàng)?