• Java 转型问题(向上转型和向下转型)


    Java 转型问题其实并不复杂,只要记住一句话:父类引用指向子类对象。

     1 public class Zhuanxing1 {
     2     static class Father {
     3         public int money = 1;
     4 
     5         public Father() {
     6             System.out.println("father constructor " + money);
     7             money = 2;
     8             showMoney();
     9         }
    10 
    11         public void showMoney() {
    12             System.out.println("father : i have " + money);
    13         }
    14     }
    15 
    16     static class Son extends Father {
    17         public int money = 3;
    18 
    19         public Son() {
    20             System.out.println("son constructor " + money);
    21             money = 4;
    22             showMoney();
    23         }
    24 
    25         public void showMoney() {
    26             System.out.println("son: i have " + money);
    27         }
    28     }
    29 
    30     public static void main(String[] args) {
    31         Father father = new Son();
    32         father.showMoney();
    33         System.out.println("this gay have $ " + father.money);
    34     }
    35 }

      

    father constructor 1
    son: i have 0
    son constructor 3
    son: i have 4
    son: i have 4
    this gay have $ 2

    什么叫父类引用指向子类对象?

    从 2 个名词开始说起:向上转型(upcasting) 、向下转型(downcasting)

    举个例子:有2个类,Father 是父类,Son 类继承自 Father。

    第 1 个例子:

    Father f1 = new Son();   // 这就叫 upcasting (向上转型)
    // 现在 f1 引用指向一个Son对象
    
    Son s1 = (Son)f1;   // 这就叫 downcasting (向下转型)
    // 现在f1 还是指向 Son对象

    第 2 个例子:

    Father f2 = new Father();
    Son s2 = (Son)f2;       // 出错,子类引用不能指向父类对象

    你或许会问,第1个例子中:Son s1 = (Son)f1; 问为什么是正确的呢。

    很简单因为 f1 指向一个子类对象,Father f1 = new Son(); 子类 s1 引用当然可以指向子类对象了。

    而 f2 被传给了一个 Father 对象,Father f2 = new Father(); 子类 s2 引用不能指向父类对象。

    总结:

    1、父类引用指向子类对象,而子类引用不能指向父类对象。

    2、把子类对象直接赋给父类引用叫upcasting向上转型,向上转型不用强制转换吗,如:

    Father f1 = new Son();

    3、把指向子类对象的父类引用赋给子类引用叫向下转型(downcasting),要强制转换,如:

    f1 就是一个指向子类对象的父类引用。把f1赋给子类引用 s1 即 Son s1 = (Son)f1;

    其中 f1 前面的(Son)必须加上,进行强制转换。

    一、向上转型。

    通俗地讲即是将子类对象转为父类对象。此处父类对象可以是接口。

    1、向上转型中的方法调用:

    实例

     1 public class Animal {
     2 
     3     public void eat() {
     4         System.out.println("animal eatting...");
     5     }
     6 }
     7 
     8 class Bird extends Animal {
     9 
    10     public void eat() {
    11         System.out.println("bird eatting...");
    12     }
    13 
    14     public void fly() {
    15 
    16         System.out.println("bird flying...");
    17     }
    18 }
    19 
    20 class Main {
    21     public static void doEat(Animal h) {
    22         h.eat();
    23     }
    24 
    25     public static void main(String[] args) {
    26 
    27         Animal b = new Bird(); //向上转型
    28         b.eat();
    29         //! error: b.fly(); b虽指向子类对象,但此时丢失fly()方法
    30         Animail c1 = new Animal();
    31         Bird c2 = new Bird();
    32         doEat(c1);
    33         doEat(c2);//此处参数存在向上转型
    34     }
    35 }
    View Code

    注意这里的向上转型:

    Animal b=new Bird(); //向上转型
    b.eat();

    此处将调用子类的 eat() 方法。原因:b 实际指向的是 Bird 子类,故调用时会调用子类本身的方法。

    需要注意的是向上转型时 b 会遗失除与父类对象共有的其他方法。如本例中的 fly 方法不再为 b 所有。

    2、向上转型的作用

    看上面的代码:

    public static void doEate(Animail h) {
        h.sleep();
    }

    这里以父类为参数,调有时用子类作为参数,就是利用了向上转型。这样使代码变得简洁。不然的话,如果 doEate 以子类对象为参数,则有多少个子类就需要写多少个函数。这也体现了 JAVA 的抽象编程思想。

    二、向下转型。

    与向上转型相反,即是把父类对象转为子类对象。

    实例

     1 public class Animail {
     2     private String name="Animail";
     3     public void eat(){
     4         System.out.println(name+" eate");
     5     }
     6 }
     7 
     8 class Human extends Animail{
     9     private String name="Human";
    10     public void eat(){
    11         System.out.println(name+" eate");
    12     }
    13 }
    14 
    15 class Main {
    16     public static void main(String[] args) {
    17         Animail a1=new Human();//向上转型
    18         Animail a2=new Animail();
    19         Human b1=(Human)a1;// 向下转型,编译和运行皆不会出错
    20  //       Human c=(Human)a2;//不安全的向下转型,编译无错但会运行会出错
    21     }
    22 }
    View Code
    Animail a1=new Human();//向上转型
    Human b1=(Human)a1;// 向下转型,编译和运行皆不会出错

    这里的向下转型是安全的。因为 a1 指向的是子类对象。

    Animail a2=new Animail();
    Human c=(Human)a2;//不安全的向下转型,编译无错但会运行会出错
     

    运行出错:

    Exception in thread "main" java.lang.ClassCastException: study.转型实例.Animail cannot be cast to study.转型实例.Human
    at study.转型实例.Main.main(Main.java:8)

    向下转型的作用

    向上转型时 b会遗失除与父类对象共有的其他方法;可以用向下转型在重新转回,这个和向上转型的作用要结合理解。

    三、当转型遇到重写和同名数据

    看下面一个例子,你觉得它会输出什么?

     1 public class Zhuanxing3 {
     2     public static void main(String[] args) {
     3         B b = new B();
     4         A a = (A) b;//此处向上转型
     5 
     6         b.print();
     7         System.out.println(b.i);
     8         b.speek();
     9         System.out.println("---------------------------------------");
    10 
    11         a.print();
    12         System.out.println(a.i);
    13         ((B) a).speek();//a在创建时虽然丢失了speek方法但是向下转型又找回了
    14 
    15     }
    16 }
    17 
    18 class A {
    19     public int i = 10;
    20 
    21     public A() {
    22         System.out.println("我是A构造函数");
    23     }
    24 
    25     public void print() {
    26         System.out.println("我是A中的函数");
    27     }
    28 }
    29 
    30 class B extends A {
    31     public int i = 20;
    32 
    33     public B() {
    34         System.out.println("我是B构造函数");
    35     }
    36 
    37     public void print() {
    38         System.out.println("我是B中的函数,我重写了A中的同名函数");
    39     }
    40 
    41     public void speek() {
    42         System.out.println("向上转型时我会丢失");
    43     }
    44 }
    View Code

    结果

    我是A构造函数
    我是B构造函数
    我是B中的函数,我重写了A中的同名函数
    20
    向上转型时我会丢失
    ---------------------------------------
    我是B中的函数,我重写了A中的同名函数
    10
    向上转型时我会丢失

    我们发现同名数据是根据创建对象的对象类型而确定,而这个子类重写的函数涉及了多态,重写的函数不会因为向上转型而丢失

    多态存在的三个必要条件

    • 继承
    • 重写
    • 父类引用指向子类对象

    所以不要弄混淆了,父类的方法在重写后会被子类覆盖,当需要在子类中调用父类的被重写方法时,要使用super关键字

  • 相关阅读:
    部署应用映射外部目录、迁移与备份、容器保存镜像、镜像打压成压缩包、压缩包恢复为镜像、dockerfiles、私有仓库、docker-compose、部署多应用、容器间通信
    docker的介绍、架构图、乌班图、安装、远程仓库、镜像操作、容器操作、应用部署、
    flask-script(制定命令)、sqlschemy、orm的使用、线程安全、增删查改、多表操作、flask-sqlalchemy
    g对象、flask-session、数据库连接池、wtforms(forms组件)、信号
    中间件、猴子补丁、蓝图、请求上下文执行流程
    flask配置文件、模板、request对象的属性和方法、响应对象方法、闪现、session的使用、请求扩展、全局标签、全局过滤器、
    flask入门、配置文件、路由系统、路由的本质、CBV
    基本权限chmod、软件管理-二进制安装、源码安装、进程管理、系统服务、
    对爬取京东商品按照标题为其进行自动分类---基于逻辑回归的文本分类
    学习进度3.16
  • 原文地址:https://www.cnblogs.com/cxxjohnson/p/14670131.html
Copyright © 2020-2023  润新知