今天重讀了一下向上轉型與向下轉型,有些新的體會,瞭解了向上轉型的好處,及如何向下轉型。在此分享給你們。java
向上轉型是用來表現新類和基類之間的關係。在傳統中,由導出類轉型成基類,在繼承圖中是向上移動的。所以稱做向上轉型。因爲向上轉型是從一個較專用類型向較通用類型轉換,因此老是安全的。也就是說,導出類是基類的一個超集。它可能比基類含有更多的方法。但他必須具有基類中所含有的方法。
咱們來看一個例子。編程
class Car { public void run() { System.out.println("這是父類run()方法"); } } public class Benz extends Car { public void run() { System.out.println("這是Benz的run()方法"); } public void price() { System.out.println("Benz:800000$"); } public static void main(String[] args) { Car car = new Benz(); car.run(); //car.price();程序報錯 } }
運行後輸出。這是Benz的run()方法。
可是當咱們用car這個對象去調用Benz類中price這個方法時,就會報錯。
這就是由於咱們此處進行的向上轉型,car這個對象雖然指向子類,可是子類因爲進行了向上轉型,就失去了使用父類中所沒有的方法的「權利」,在此處就是不能調用price()這個方法。
那麼向上轉型到底有什麼用呢,到目前爲止咱們不只看不到它的好處,反而發現使用了向上轉型後反而不能調用子類所特有的方法了。那麼向上轉型的做用究竟是什麼呢,咱們一塊兒來看下面的代碼:安全
class Car { public void run() { System.out.println("這是父類run()方法"); } public void speed() { System.out.println("speed:0"); } } class BMW extends Car { public void run() { System.out.println("這是BMW的run()方法"); } public void speed() { System.out.println("speed:80"); } } public class Benz extends Car { public void run() { System.out.println("這是Benz的run()方法"); } public void speed() { System.out.println("speed:100"); } public void price() { System.out.println("Benz:800000$"); } public static void main(String[] args) { show(new Benz());//向上轉型實現 show(new BMW()); } public static void show(Car car) {//父類實例做爲參數 car.run(); car.speed(); } }
上面代碼中ide
public static void main(String[] args) { show(new Benz()); show(new BMW()); } public static void show(Car car) { car.run(); car.speed(); }
就體現了向上轉型的優勢,這也體現了Java抽象編程的思想。若是此處沒有向上轉型,要實現show每一個子類的功能,那麼有幾個子類就要寫多少函數。代碼以下:函數
public static void main(String[] args) { show(new Benz()); show(new BMW()); } public static void show(Benz benz) { benz.run(); benz.speed(); } public static void show(BMW bmw) { bmw.run(); bmw.speed(); }
試想一下,一旦有不少子類,那麼這個工做量將會比沒有使用向上轉型大不少。這也代表向上轉型還有個優勢就是提升了代碼的簡潔性。
咱們再來一種帶着static的特殊調用狀況。code
public class Animal { String name = "我是動物"; static int age = 20; public void eat() { System.out.println("動物能夠吃飯"); } public static void sleep() { System.out.println("動物能夠睡覺"); } public void run(){ System.out.println("動物能夠奔跑"); } public static void main(String[] args) { Animal am = new Dog(); am.eat(); am.sleep(); am.run(); //am.watchdog();這裏會報錯 System.out.println(am.name); System.out.println(am.age); } } class Dog extends Animal { String name = "小狗"; static int age = 60; public void eat() { System.out.println("小狗能夠吃飯"); } public static void sleep() { System.out.println("小狗能夠睡覺"); } public void watchdog() { System.out.println("小狗能夠看門"); } }
運行結果:
對象
可是能夠看到代碼塊中,直接調用Dog的watchdog()方法會報錯。
blog
這就是由於咱們此處進行的向上轉型,am這個對象雖然指向子類,可是子類因爲進行了向上轉型,就失去了使用父類中所沒有的方法的「權利」,在此處就是不能調用watchdog()這個方法。
並且結果裏也能夠看到,睡覺是引用的父類「Animal」的睡覺方法,這是由於Animal的睡覺方法爲靜態方法,能夠總結以下:
若是是訪問成員變量,編譯的話就是看父類,運行一樣是看父類。
若是訪問的方法,編譯就看父類,運行則看子類。
若是是靜態方法,編譯和運行都是看父類。繼承
先看一個錯誤的例子io
public class Animal { public void eat(){ System.out.println("Animal eat()"); } } public class Dog extends Animal { @Override public void eat(){ System.out.println("Dog eat"); } } public class Test { public static void main(String[] args) { //向下轉型 Animal animal = new Animal(); ((Dog)animal).eat(); } }
運行結果:
Exception in thread "main" java.lang.ClassCastException: com.hello.test.Animal cannot be cast to com.hello.test.Dog
at com.hello.test.Test.main(Test.java:7)
從上述例子來看,Java彷佛並不支持向下轉型,真是如此嗎?其實否則,Java一樣支持向下轉型,只是向下轉型是有條件的——只有引用子類對象的父類引用才能被向下轉型爲子類對象。也就是說,向下轉型以前,必須先向上轉型。
public class Animal { public void eat(){ System.out.println("Animal eat()"); } } public class Dog extends Animal { @Override public void eat(){ System.out.println("Dog eat"); } } public class Test { public static void main(String[] args) { //向上轉型 Animal animal = new Dog(); //向下轉型 ((Dog)animal).eat(); } }
運行結果: Dog eat