java向上转型和向下转型

2021/01/20 Java基础知识 共 1557 字,约 5 分钟
闷骚的程序员

1. 向上转型

  1. 向上转型本质是类型转换的一种,属于自动转换操作。
  2. 向上转型只能发生在父子类之间,目的是将子类的实例化对象向上转换为对应的父类对象。
  3. 向上转型的父类可以是子类的直接父类,也可以是层级较多的间接父类,还可以是层级更好的接口。
  4. 子类实例化对象向上转型的本质:
    向上转型为父类对象后,该对象的引用地址实际上依旧指向对应的子类对象堆内存地址;向上转型只不过是语法糖,编译器允许不同的子类对象都转换为其某个父类型。
    因为子类继承了父类中的成员变量和成员方法,因此向上转型的对象真正调用的始终是对应子类里面的方法和变量,只不过如果子类没覆盖的话,这些东西将是继承自父类而来的。
  5. 通过向上转型的对象调用方法时的原则如下:
    (1)如果当前父类的所有子类都没有覆盖对应的方法,则此时调用的是父类的方法。
    (2)如果当前父类和当前子类之间的继承链里存在某个子类覆盖了对应的方法,则此时调用的是继承链里距离当前实例化子类最近的那个子类覆盖后的方法(最常见的实际上是当前实例化子类自己覆盖了对应的而方法)。

对向上转型的解释:
tips:如果发生向上转型的父子类之间并不是直接关系,可能是爷孙甚至是多层关系,此时发生向上转型后,对应的父类对象的引用会指向当前父类和真实的实例化子类对象之间所有的中间对象的堆内存。
举例:

  1. 有继承关系:D->C->B->A(D继承C,C继承B,B继承A)。
  2. 发生向上转型:A a = new D();
  3. 现象:a的引用地址,指向A类的实例;指向B类的实例;指向C类的实例;指向D类的实例。
  4. 观察调用原则:
    (1)A中有方法test(),B,C,D都没有覆盖,此时a.test()调用的即是A中的test()方法。
    (2)B覆盖了A中继承而来的方法test(),此时a.test()调用的即是B中覆盖后的test()方法。
    (3)B覆盖了A中继承而来的方法test(),C又覆盖了从B中继承而来的test(),此时a.test()调用的即是C中的test()方法。
    (4)B覆盖了A中继承而来的方法test(),C覆盖了从B中继承而来的方法test(),D又覆盖了从C中继承而来的方法test(),此时a.test()调用的即是D中的test()方法。
    (5)其他复杂场景,以继承链依次类推。

2. 向下转型

  1. 向下转型本质是类型转换的一种,属于强制转换操作。
  2. 向下转型即父类对象转换为对应的子类对象。
  3. 当子类扩展了自己独有的新方法时(该方法并不是继承自上游的父类们),就必须进行向下转型将父类对象转换为对应子类对象,才能调用对应子类的独有方法,否则将无法调用。
  4. 向下转型前,必须进行向上转型,如果不,也可直接向下转型,编译不报错,但运行会报类转换异常。

对向下转型的解释:
tips:向下转型前必须进行对应的向上转型,否则对应的子类实例化对象和对应的父类之间没有产生类型转换关系。
如果发生向上转型的父子类之间并不是直接关系,可能是爷孙甚至是多层关系,此时发生向上转型后,进行向下转型,对应的父类对象实际上可以转换到当前父类和实例化子类之间的继承链中的任意类型。
举例:

  1. 有继承关系:D->C->B->A(D继承C,C继承B,B继承A)。
  2. 发生向上转型:A a = new D();
  3. 现象:a的引用地址,指向A类的实例;指向B类的实例;指向C类的实例;指向D类的实例。
  4. B中有自己的方法b();C中有自己的方法c();D中有自己的方法d()。
  5. 要想调用继承链中子类独有的方法,则需要将向上转型后的父类对象转换为对应的子类对象。
    (1)a对象若想调用b()方法,需要向下转型:B b = (B)a。
    (2)a对象若想调用c()方法,需要向下转型:C c = (C)a。
    (3)a对象若想调用d()方法,需要向下转型:D d = (D)a。
    (4)其他复杂场景,以继承链依次类推。

文档信息

Search

    Table of Contents