Java物件型別向上轉型和向下轉型
-
引入:
-
子類可以繼承父類中的所有屬性和方法,包括private修飾的屬性和方法;但是子類只是擁有父類private修飾的屬性和方法,卻不能直接使用它,也就是無法直接訪問到他們(子類可以通過呼叫父類的public宣告的get方法來獲取父類的private屬性,但無法訪問父類的private方法)
-
同時子類可以對繼承的方法進行重寫,並且新建自己獨有的方法
向上轉型
public class Fruit { public void show(){ System.out.println("this is a fruit!"); } }
有一個Apple類繼承自Fruit類,該類有自己的方法eat(),並且重寫了父類的show()方法,程式碼如下:
public class Apple extends Fruit{ @Override//重寫標誌!!! public void show(){ System.out.println("this is a apple!"); } public void eat(){ System.out.println("要多吃蘋果!"); } }
例項化Apple類,並新建一個Fruit類的引用變數引用該例項,呼叫例項的show()方法:
public class Test { public static void main(String[] args) { /*父類的引用指向子類!方法的呼叫只和左邊、定義的資料型別有關*/ Fruit fruit = new Apple();//子類重寫父類的方法 fruit.show();//this is a apple! System.out.println("=========="); fruit.eat();//報錯!!!必須是繼承父類的方法 } }
分析:這裡用到了向上轉型!就是用父類的引用變數去引用子類的例項,這是允許的。當向上轉型之後,父類引用變數可以訪問子類中屬於父類的屬性和方法,但是不能訪問子類獨有的屬性和方法。上面舉例中由於子類重寫了父類的show()方法,所以呼叫的show()方法是子類的show()方法,輸出結果為:“this is a apple”而呼叫子類的eat()方法則會報錯!
以上兩張圖簡單總結規律:
-
看有沒有繼承標誌@Override!!!需要注意的是沒有這個標誌,但方法完全一致,不叫重寫!必須有標誌
-
如果沒有繼承關係:父類的引用指向不了子類,就呼叫的自己本身(父類)的方法
-
有繼承關係:父類的引用指向子類,呼叫繼承自父類的方法(方法被重寫)
向下轉型
並不是所有的物件都可以向下轉型,只有當這個物件原本就是子類物件通過向上轉型得到的時候才能夠成功轉型。
例項化Apple類,並新建一個Fruit類的引用變數“fruit”引用該例項,然後新建一個Apple類的引用變數,引用向下轉型的“fruit”變數,程式碼如下:
Fruit fruit = new Apple(); Apple apple = (Apple) fruit;
上述程式碼是允許的,因為fruit引用的物件原本就是Apple物件向上轉型得到的,在對fruit向下轉型後得到的還是Apple類的物件,能夠被Apple類的引用變數引用。
假設有一個Orange類繼承自Fruit類,程式碼如下:
public class Orange extends Fruit { @Override public void show(){ System.out.println("this is a orange"); } public void test(){ System.out.println("I am a orange"); } }
例項化Apple類,並新建一個Fruit類的引用變數“fruit”引用該例項,然後新建一個Orange類的引用變數,引用向下轉型的“fruit”變數,程式碼如下:
Fruit fruit = new Apple(); Orange orange = (Orange) fruit;
上述程式碼雖然能夠編譯成功,但是在執行的時候會報錯,因為fruit物件是由Apple物件向上轉型得到的,只能夠向下轉型成Apple物件,不能夠向下轉型成Orange物件。
轉型的好處
通過向上向下轉型肯定是有好處的,比如可以減少程式設計程式碼。
假設在主類中定義了一個run()方法,該方法傳入一個Fruit引數,並呼叫了Fruit物件的show()方法,程式碼如下:
public class Test { public static void main(String[] args) { run(new Fruit()); run(new Apple()); run(new Orange()); } public static void run(Fruit fruit){ fruit.show(); } } //this is a fruit! //this is a apple! //this is a orange