面试常考基础,向上转型与向下转型(穿插讲解多态的编译时多态和运行时多态)
前言
这个跟继承一起考,如果了解好这个后,会帮助你加强对多态的概念。就不会当听到多态,第一时间想到的时候就是重写和重载,但是应该不只是想到这一些,还得想到并理解好编译时多态和运行时多态。
正文
向上转型
在说概念之前,我感觉应该先来个例子吧来看看吧
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();
}
}
运行截图:

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();
}
}
运行截图:

这里也看出来了,其实向上转型的含义就是创建一个子类对象,将其当成父类对象来使用。
错误的原因很简单,就是b 的编译时类型是 Animal,而 Animal 类里并没有声明 bark() 方法,所以编译器直接报错:找不到符号。这就是向上转型的缺点就是无法调用子类所特有的方法,但是你们也看到了截图里面b.bark();旁边有ai提示我该怎么改,这个也就是后面的向上转型了。
在这里我就是一起讲一下运行时多态,我们说到的向上转型是创建一个子类对象,将其当成父类对象来使用,也可以说成父类引用指向子类对象。(这里参考了https://blog.csdn.net/xylitolz/article/details/115800775)
父类只能执行那些在父类中声明、被子类覆盖了的子类方法,而不能执行子类新增加的成员方法。在编译时期,首先会去查看父类里面有没有这个方法,如果没有的话向上继续查找,直到找到Object类如果还没有的话就报错,如果有的话,到运行阶段,再去看一下子类中有没有覆盖该方法,如果覆盖了,则执行子类覆盖的方法。如果没有则执行父类中原本的方法。这个结合我上面的例子。
当子类和父类有相同属性时,父类还是会执行自己所拥有的属性,若父类中没有的属性子类中有,在编译时期就会报错
运行截图:


对于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();
}
}
运行截图:


浙公网安备 33010602011771号