面试常考基础,向上转型与向下转型(穿插讲解多态的编译时多态和运行时多态)

前言

这个跟继承一起考,如果了解好这个后,会帮助你加强对多态的概念。就不会当听到多态,第一时间想到的时候就是重写和重载,但是应该不只是想到这一些,还得想到并理解好编译时多态和运行时多态。

正文

向上转型

在说概念之前,我感觉应该先来个例子吧来看看吧

class Animal{
   public void eat(){
       System.out.println("动物吃");
   }
}
class Dog extends Animal{
   @Override
   public void eat() {
       System.out.println("狗吃");
   }
}
public class Test {
   public static void main(String[] args) {
       Animal a = new Animal();
       a.eat();
       Animal b = new Dog();
       b.eat();
   }
}

运行截图:
image

a.eat(),运行结果是“动物吃”
b.eat(),运行结果是“狗吃”,由于b中,Dog类重写了eat(),且在向上转型中,子类如果有对应的函数,且不是子类所特有的,父类也有该函数,那么就选择执行子类中的函数;如果子类没有该函数,那么去看父类中的情况,如果有就执行父类中的函数。
这里就体现了向上转型十分的灵活,但是他也有缺点,就是我前面也提到了的执行子类中的函数时,需不是子类所特有的。

而在这里我就穿个

如以下的例子

package com.atguigu.daijia.customer.service.impl;

class Animal{
    public void eat(){
        System.out.println("动物吃");
    }
}
class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃");
    }

    public void bark(){
        System.out.println("狗吠");
    }
}
public class Test {
    public static void main(String[] args) {
        Animal a = new Animal();
        a.eat();
        Animal b = new Dog();
        b.bark();
    }
}

运行截图:
image

这里也看出来了,其实向上转型的含义就是创建一个子类对象,将其当成父类对象来使用。
错误的原因很简单,就是b 的编译时类型是 Animal,而 Animal 类里并没有声明 bark() 方法,所以编译器直接报错:找不到符号。这就是向上转型的缺点就是无法调用子类所特有的方法,但是你们也看到了截图里面b.bark();旁边有ai提示我该怎么改,这个也就是后面的向上转型了。

在这里我就是一起讲一下运行时多态,我们说到的向上转型是创建一个子类对象,将其当成父类对象来使用,也可以说成父类引用指向子类对象。(这里参考了https://blog.csdn.net/xylitolz/article/details/115800775)

父类只能执行那些在父类中声明、被子类覆盖了的子类方法,而不能执行子类新增加的成员方法。在编译时期,首先会去查看父类里面有没有这个方法,如果没有的话向上继续查找,直到找到Object类如果还没有的话就报错,如果有的话,到运行阶段,再去看一下子类中有没有覆盖该方法,如果覆盖了,则执行子类覆盖的方法。如果没有则执行父类中原本的方法。这个结合我上面的例子。

当子类和父类有相同属性时,父类还是会执行自己所拥有的属性,若父类中没有的属性子类中有,在编译时期就会报错
运行截图:

image
image
对于static方法还是会执行父类中的方法,这是由于在运行时,虚拟机已经认定static方法属于哪个类。“重写”只能适用于实例方法,不能用于静态方法。在利用引用访问对象的属性或静态方法时,是引用类型决定了实际上访问的是哪个属性,而非当前引用实际代表的是哪个类。

既然说了运行时多态,就随便把编译时多态讲了,其实从上面我们就发现了父子之间同名函数使用的一些逻辑了把,重写对应运行时多态,那么其实重载对应的是编译时多态

拿重载来说,在同一个类中,出现了多个同名的方法,而区分他们是由于形参列表不同,而根据参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法中的哪一个。

向下转型

在上面说,若想调用子类独有的函数,应该进行向下转型。将父类对象再还原为子类对象,就是对原本的子类向上转型之后可以当成父类对象使用,然后再向下转型为子类对象。

package com.atguigu.daijia.customer.service.impl;

class Animal{
  public  int speed=10;
  public void eat(){
      System.out.println("动物吃");
  }
}
class Dog extends Animal{
  @Override
  public void eat() {
      System.out.println("狗吃");
  }

  public void bark(){
      System.out.println("狗吠");
  }
}


public class Test {
  public static void main(String[] args) {
      Animal a = new Animal();
      a.eat();
      Animal b = new Dog();
      //b.bark();
      ((Dog)b).bark();
  }
}

运行截图:

image

posted @ 2025-08-15 17:45  Lxx-123  阅读(16)  评论(0)    收藏  举报