重新精读《Java 编程思想》系列之向上转型与向下转型

举报
经典鸡翅 发表于 2022/02/17 22:33:59 2022/02/17
【摘要】 前言 今天重读了一下向上转型与向下转型,有些新的体会,了解了向上转型的好处,及如何向下转型。在此分享给大家。 向上转型 向上转型是用来表现新类和基类之间的关系。在传统中,由导出类转型成基类,在继承图中是向上移动的。因此称作向上转型。由于向上转型是从一个较专用类型向较通用类型转换,所以总是安全的。也就是说,导出类是基类的...

前言

今天重读了一下向上转型与向下转型,有些新的体会,了解了向上转型的好处,及如何向下转型。在此分享给大家。

向上转型

向上转型是用来表现新类和基类之间的关系。在传统中,由导出类转型成基类,在继承图中是向上移动的。因此称作向上转型。由于向上转型是从一个较专用类型向较通用类型转换,所以总是安全的。也就是说,导出类是基类的一个超集。它可能比基类含有更多的方法。但他必须具备基类中所含有的方法。
我们来看一个例子。


   
  1. class Car {
  2. public void run() {
  3. System.out.println("这是父类run()方法");
  4. }
  5. }
  6. public class Benz extends Car {
  7. public void run() {
  8. System.out.println("这是Benz的run()方法");
  9. }
  10. public void price() {
  11. System.out.println("Benz:800000$");
  12. }
  13. public static void main(String[] args) {
  14. Car car = new Benz();
  15. car.run();
  16. //car.price();程序报错
  17. }
  18. }

运行后输出。这是Benz的run()方法。
但是当我们用car这个对象去调用Benz类中price这个方法时,就会报错。
这就是因为我们此处进行的向上转型,car这个对象虽然指向子类,但是子类由于进行了向上转型,就失去了使用父类中所没有的方法的“权利”,在此处就是不能调用price()这个方法。
那么向上转型到底有什么用呢,到目前为止我们不仅看不到它的好处,反而发现使用了向上转型后反而不能调用子类所特有的方法了。那么向上转型的作用到底是什么呢,我们一起来看下面的代码:


   
  1. class Car {
  2. public void run() {
  3. System.out.println("这是父类run()方法");
  4. }
  5. public void speed() {
  6. System.out.println("speed:0");
  7. }
  8. }
  9. class BMW extends Car {
  10. public void run() {
  11. System.out.println("这是BMW的run()方法");
  12. }
  13. public void speed() {
  14. System.out.println("speed:80");
  15. }
  16. }
  17. public class Benz extends Car {
  18. public void run() {
  19. System.out.println("这是Benz的run()方法");
  20. }
  21. public void speed() {
  22. System.out.println("speed:100");
  23. }
  24. public void price() {
  25. System.out.println("Benz:800000$");
  26. }
  27. public static void main(String[] args) {
  28. show(new Benz());//向上转型实现
  29. show(new BMW());
  30. }
  31. public static void show(Car car) {//父类实例作为参数
  32. car.run();
  33. car.speed();
  34. }
  35. }

上面代码中


   
  1. public static void main(String[] args) {
  2. show(new Benz());
  3. show(new BMW());
  4. }
  5. public static void show(Car car) {
  6. car.run();
  7. car.speed();
  8. }

就体现了向上转型的优点,这也体现了Java抽象编程的思想。如果此处没有向上转型,要实现show每个子类的功能,那么有几个子类就要写多少函数。代码如下:


   
  1. public static void main(String[] args) {
  2. show(new Benz());
  3. show(new BMW());
  4. }
  5. public static void show(Benz benz) {
  6. benz.run();
  7. benz.speed();
  8. }
  9. public static void show(BMW bmw) {
  10. bmw.run();
  11. bmw.speed();
  12. }

试想一下,一旦有很多子类,那么这个工作量将会比没有使用向上转型大很多。这也表明向上转型还有个优点就是提高了代码的简洁性。
我们再来一种带着static的特殊调用情况。


   
  1. public class Animal {
  2. String name = "我是动物";
  3. static int age = 20;
  4. public void eat() {
  5. System.out.println("动物可以吃饭");
  6. }
  7. public static void sleep() {
  8. System.out.println("动物可以睡觉");
  9. }
  10. public void run(){
  11. System.out.println("动物可以奔跑");
  12. }
  13. public static void main(String[] args) {
  14. Animal am = new Dog();
  15. am.eat();
  16. am.sleep();
  17. am.run();
  18. //am.watchdog();这里会报错
  19. System.out.println(am.name);
  20. System.out.println(am.age);
  21. }
  22. }
  23. class Dog extends Animal {
  24. String name = "小狗";
  25. static int age = 60;
  26. public void eat() {
  27. System.out.println("小狗可以吃饭");
  28. }
  29. public static void sleep() {
  30. System.out.println("小狗可以睡觉");
  31. }
  32. public void watchdog() {
  33. System.out.println("小狗可以看门");
  34. }
  35. }

运行结果:

但是可以看到代码块中,直接调用Dog的watchdog()方法会报错。

这就是因为我们此处进行的向上转型,am这个对象虽然指向子类,但是子类由于进行了向上转型,就失去了使用父类中所没有的方法的“权利”,在此处就是不能调用watchdog()这个方法。
而且结果里也可以看到,睡觉是引用的父类“Animal”的睡觉方法,这是因为Animal的睡觉方法为静态方法,可以总结如下:
如果是访问成员变量,编译的话就是看父类,运行同样是看父类。
如果访问的方法,编译就看父类,运行则看子类。
如果是静态方法,编译和运行都是看父类。

向下转型

先看一个错误的例子


   
  1. public class Animal {
  2. public void eat(){
  3. System.out.println("Animal eat()");
  4. }
  5. }
  6. public class Dog extends Animal {
  7. @Override
  8. public void eat(){
  9. System.out.println("Dog eat");
  10. }
  11. }
  12. public class Test {
  13. public static void main(String[] args) {
  14. //向下转型
  15. Animal animal = new Animal();
  16. ((Dog)animal).eat();
  17. }
  18. }

运行结果:
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同样支持向下转型,只是向下转型是有条件的——只有引用子类对象的父类引用才能被向下转型为子类对象。也就是说,向下转型之前,必须先向上转型。


   
  1. public class Animal {
  2. public void eat(){
  3. System.out.println("Animal eat()");
  4. }
  5. }
  6. public class Dog extends Animal {
  7. @Override
  8. public void eat(){
  9. System.out.println("Dog eat");
  10. }
  11. }
  12. public class Test {
  13. public static void main(String[] args) {
  14. //向上转型
  15. Animal animal = new Dog();
  16. //向下转型
  17. ((Dog)animal).eat();
  18. }
  19. }

运行结果:
Dog eat

文章来源: blog.csdn.net,作者:经典鸡翅,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/hanqing456/article/details/111878933

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。