1.5 对象类型转换:向上转型和向下转型
將一個類型強制轉換成另一個類型的過程被稱為類型轉換。本節所說的對象類型轉換,是指存在繼承關系的對象,不是任意類型的對象。當對不存在繼承關系的對象進行強制類型轉換時,會拋出 Java 強制類型轉換(java.lang.ClassCastException)異常。
Java 語言允許某個類型的引用變量引用子類的實例,而且可以對這個引用變量進行類型轉換。Java 中引用類型之間的類型轉換(前提是兩個類是父子關系)主要有兩種,分別是向上轉型(upcasting)和向下轉型(downcasting)。
1)向上轉型
父類引用指向子類對象為向上轉型,語法格式如下:
fatherClass obj = new sonClass();其中,fatherClass 是父類名稱或接口名稱,obj 是創建的對象,sonClass 是子類名稱。
向上轉型就是把子類對象直接賦給父類引用,不用強制轉換。使用向上轉型可以調用父類類型中的所有成員,不能調用子類類型中特有成員,最終運行效果看子類的具體實現。
2)向下轉型
與向上轉型相反,子類對象指向父類引用為向下轉型,語法格式如下:
sonClass obj = (sonClass) fatherClass;其中,fatherClass 是父類名稱,obj 是創建的對象,sonClass 是子類名稱。
向下轉型可以調用子類類型中所有的成員,不過需要注意的是如果父類引用對象指向的是子類對象,那么在向下轉型的過程中是安全的,也就是編譯是不會出錯誤。但是如果父類引用對象是父類本身,那么在向下轉型的過程中是不安全的,編譯不會出錯,但是運行時會出現我們開始提到的 Java 強制類型轉換異常,一般使用 instanceof 運算符來避免出此類錯誤。
例如,Animal 類表示動物類,該類對應的子類有 Dog 類,使用對象類型表示如下:
Animal animal = new Dog(); // 向上轉型,把Dog類型轉換為Animal類型 Dog dog = (Dog) animal; // 向下轉型,把Animal類型轉換為Dog類型例 1
下面通過具體的示例演示對象類型的轉換。例如,父類 Animal 和子類 Cat 中都定義了實例變量 name、靜態變量 staticName、實例方法 eat() 和靜態方法 staticEat()。此外,子類 Cat 中還定義了實例變量 str 和實例方法 eatMethod()。
父類 Animal 的代碼如下:
public class Animal {public String name = "Animal:動物";public static String staticName = "Animal:可愛的動物";public void eat() {System.out.println("Animal:吃飯");}public static void staticEat() {System.out.println("Animal:動物在吃飯");} }子類 Cat 的代碼如下:
public class Cat extends Animal {public String name = "Cat:貓";public String str = "Cat:可愛的小貓";public static String staticName = "Dog:我是喵星人";public void eat() {System.out.println("Cat:吃飯");}public static void staticEat() {System.out.println("Cat:貓在吃飯");}public void eatMethod() {System.out.println("Cat:貓喜歡吃魚");}public static void main(String[] args) {Animal animal = new Cat();Cat cat = (Cat) animal; // 向下轉型System.out.println(animal.name); // 輸出Animal類的name變量System.out.println(animal.staticName); // 輸出Animal類的staticName變量animal.eat(); // 輸出Cat類的eat()方法animal.staticEat(); // 輸出Animal類的staticEat()方法System.out.println(cat.str); // 調用Cat類的str變量cat.eatMethod(); // 調用Cat類的eatMethod()方法} }- 通過引用類型變量來訪問所引用對象的屬性和方法時,Java 虛擬機將采用以下綁定規則:實例方法與引用變量實際引用的對象的方法進行綁定,這種綁定屬于動態綁定,因為是在運行時由 Java虛擬機動態決定的。例如,animal.eat() 是將 eat() 方法與 Cat 類綁定。
- 靜態方法與引用變量所聲明的類型的方法綁定,這種綁定屬于靜態綁定,因為是在編譯階段已經做了綁定。例如,animal.staticEat()是將 staticEat() 方法與 Animal 類進行綁定。
- 成員變量(包括靜態變量和實例變量)與引用變量所聲明的類型的成員變量綁定,這種綁定屬于靜態綁定,因為在編譯階段已經做了綁定。例如,animal.name 和animal.staticName 都是與 Animal 類進行綁定。
對于 Cat 類,運行時將會輸出如下結果:
Animal:動物 Animal:可愛的動物 Cat:吃飯 Animal:動物在吃飯 Cat:可愛的小貓 Cat:貓喜歡吃魚強制對象類型轉換
Java 編譯器允許在具有直接或間接繼承關系的類之間進行類型轉換。對于向下轉型,必須進行強制類型轉換;對于向上轉型,不必使用強制類型轉換。
例如,對于一個引用類型的變量,Java 編譯器按照它聲明的類型來處理。如果使用 animal 調用 str 和 eatMethod() 方法將會出錯,如下:
animal.str = ""; // 編譯出錯,提示Animal類中沒有str屬性 animal.eatMethod(); // 編譯出錯,提示Animal類中沒有eatMethod()方法如果要訪問 Cat 類的成員,必須通過強制類型轉換,如下:
((Cat)animal).str = ""; // 編譯成功 ((Cat)animal).eatMethod(); // 編譯成功把 Animal 對象類型強制轉換為 Cat 對象類型,這時上面兩句編譯成功。對于如下語句,由于使用了強制類型轉換,所以也會編譯成功,例如:
Cat cat = (Cat)animal; // 編譯成功,將Animal對象類型強制轉換為Cat對象類型instanceof 是 Java 的保留關鍵字。它的作用是測試它左邊的對象是否是它右邊的類的實例,返回 boolean 的數據類型。
類型強制轉換時想運行成功就必須保證父類引用指向的對象一定是該子類對象,最好使用 instanceof 運算符判斷后,再強轉,例如:
Animal animal = new Cat(); if (animal instanceof Cat) {Cat cat = (Cat) animal; // 向下轉型... }子類的對象可以轉換成父類類型,而父類的對象實際上無法轉換為子類類型。因為通俗地講,父類擁有的成員子類肯定也有,而子類擁有的成員,父類不一定有。因此,對于向上轉型,不必使用強制類型轉換。例如:
Cat cat = new Cat(); Animal animal = cat; // 向上轉型,不必使用強制類型轉換如果兩種類型之間沒有繼承關系,那么將不允許進行類型轉換。例如:
Dog dog = new Dog(); Cat cat = (Cat)dog; // 編譯出錯,不允許把Dog對象類型轉換為Cat對象類型總結
以上是生活随笔為你收集整理的1.5 对象类型转换:向上转型和向下转型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 1.4 super关键字详解
- 下一篇: 1.6 为什么使用向上转型而不直接创建子