Java同文件类的向下转型代码运行逻辑咨询
Java父类引用指向子类对象的执行逻辑解析
先把你的代码贴出来方便逐点分析:
public class Child extends Base { void show() { System.out.println("Child"); } void display(){ System.out.println("Display"); } public static void main(String[] args) { Base b=new Child(); b.show(); b.display(); } } class Base { void show() { System.out.println("Base"); } }
首先得先点明一个关键问题:这段代码其实编译阶段就会报错,后面我会详细解释原因,再拆解整个逻辑的核心原理。
1. 父类引用指向子类对象的本质
这句Base b = new Child();是Java多态的典型写法,背后的执行逻辑是:
- JVM会在堆内存中创建一个完整的
Child对象,它包含自身定义的show()、display()方法,同时继承了Base类的show()方法(但已经被Child重写覆盖)。 - 我们把这个
Child对象的引用,赋值给了类型为Base的变量b。此时b的编译类型是Base(编译器眼里它就是个Base对象),但实际指向的运行类型是Child(JVM运行时清楚它是个Child对象)。
2. b.show()的执行过程
show()方法在父类Base中定义,子类Child又重写了它,这里触发了Java的**动态绑定(运行时多态)**机制:
- 编译阶段:编译器检查
Base类中是否存在show()方法,发现存在,所以编译通过。 - 运行阶段:JVM会根据
b实际指向的对象类型(Child),去调用Child类中重写的show()方法,所以最终输出Child。
3. b.display()为什么会报错?
这是你这段代码的核心问题:display()方法只在Child类中定义,Base类里完全没有这个方法。
Java的方法调用遵循编译时检查规则:编译器只会根据变量的编译类型(这里是Base)来判断是否能调用某个方法。因为Base类中没有display(),所以编译器直接报错,根本到不了运行阶段。
如果想让display()能被正常调用,有两种解决办法:
- 在
Base类中添加display()方法(哪怕是空实现),让Child类重写它,这样通过b调用时会触发动态绑定,执行Child的display()。 - 把
b强制类型转换为Child类型:((Child) b).display(),这样编译器会识别到这是Child对象,允许调用display()。
核心原理总结
- 编译看引用类型:编译器只认变量声明的类型,调用的方法必须在该类型中存在,否则编译失败。
- 运行看实际对象类型:对于编译通过的实例方法,JVM会根据实际对象的类型来调用对应的重写方法,这就是多态的核心。
内容的提问来源于stack exchange,提问作者Abhishek Dubey
相关产品推荐
相关产品推荐

