初學者在學習向上轉型可能會很難理解,向上轉型並不能呼叫子類特有屬性和方法,我們必須先生成子類範例再賦值給父類別參照(向上轉型),然後將父類別參照向下強制轉換給子類參照(向下轉型),這樣才能呼叫子類中的所有成員。這看起來像是多次一舉,還不如直接建立子類範例。
隨著技術的提升,我們在學習其它開源專案時會發現很多地方都用了向上轉型和向下轉型的技術。本節將帶大家了解向上轉型和向下轉型的意義及使用場景。
例 1
定義父類別 Animal,程式碼如下:
public class Animal {
public void sleep() {
System.out.println("小動物在睡覺");
}
public static void doSleep(Animal animal) {
// 此時的引數是父類別物件,但是實際呼叫時傳遞的是子類物件,就是向上轉型。
animal.sleep();
}
public static void main(String[] args) {
animal.doSleep(new Cat());
animal.doSleep(new Dog());
}
}
子類 Cat 程式碼如下:
public class Cat extends Animal {
@Override
public void sleep() {
System.out.println("貓正在睡覺");
}
}
子類 Dog 程式碼如下:
public class Dog extends Animal {
@Override
public void sleep() {
System.out.println("狗正在睡覺");
}
}
輸出結果為:
貓正在睡覺
狗正在睡覺
如果不用向上轉型則必須寫兩個 doSleep 方法,一個傳遞 Cat 類物件,一個傳遞 Dog 類物件。這還是兩個子類,如果有多個子類就要寫很多相同的方法,造成重複。可以看出向上轉型更好的體現了類的多型性,增強了程式的間接性以及提高了程式碼的可延伸性。當需要用到子類特有的方法時可以向下轉型,這也就是為什麼要向下轉型。
比如設計一個父類別 FileRead 用來讀取檔案,ExcelRead 類和 WordRead 類繼承 FileRead 類。在使用程式的時候,往往事先不知道我們要讀入的是 Excel 還是 Word。所以我們向上轉型用父類別去接收,然後在父類別中實現自動系結,這樣無論你傳進來的是 Excel 還是 Word 就都能夠完成檔案讀取。
總結如下:
-
把子類物件直接賦給父類別參照是向上轉型,向上轉型自動轉換。如 Father father = new Son();
-
指向子類物件的父類別參照賦給子類參照是向下轉型,要強制轉換。使用向下轉型,必須先向上轉型,為了安全可以用 instanceof 運算子判斷。 如 father 是一個指向子類物件的父類別參照,把 father 賦給子類參照 son,即
Son son =(Son)father;
。其中 father 前面的(Son)
必須新增,進行強制轉換。
-
向上轉型不能使用子類特有的屬性和方法,只能參照父類別的屬性和方法,但是子類重寫父類別的方法是有效的。
-
向上轉型時會優先使用子類中重寫父類別的方法,如例 1 中呼叫的 sleep 方法。
-
向上轉型的作用是減少重複程式碼,可以將父類別作為引數,這樣使程式碼變得簡潔,也更好的體現了多型。