今天重读了一下向上转型与向下转型,有些新的体会,了解了向上转型的好处,及如何向下转型。在此分享给你们。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