You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何向上转型对象会调用子类重写的父类方法?对JLS规则的困惑

关于Java向上转型方法调用的JLS规范误解解析

你混淆了Java方法调用的编译阶段签名确定和运行时方法选择两个独立步骤,JLS 15.12.1只负责前者,后者有单独的规范约束。

1. 编译阶段:JLS 15.12.1的作用

JLS 15.12.1里提到的「搜索类型为变量声明类型」,是编译时用来确定方法签名的规则:

  • 当你写superclass.Identifier()时,编译器会基于superclass的声明类型Superclass去查找匹配的方法(方法名+参数列表),确保这个方法在Superclass中是可访问、存在的,否则会直接编译报错。
  • 这一步不关心变量实际指向的对象类型,只做语法和合法性检查。

2. 运行阶段:实际方法的选择规则

编译通过后,运行时会根据对象的实际类型来选择要执行的方法,对应的规范是JLS 15.12.4.4(运行时方法选择):

  • 对于实例方法调用,JVM会从实际对象的类型开始,向上遍历继承链,找到第一个重写了编译阶段确定的签名的方法,然后执行它。
  • 比如你例子里Superclass superclass = new Subclass();,实际对象是Subclass类型,所以会优先执行Subclass中重写的方法,哪怕变量声明类型是Superclass。

结合你给出的示例理解

拿JLS 8.4.8.1的Point和SlowPoint举例:

  • 编译时:如果代码是Point p = new SlowPoint(); p.move(5,5);,编译器会基于Point的类型查找move(int, int)方法,确认存在,编译通过。
  • 运行时:JVM发现实际对象是SlowPoint,而SlowPoint重写了move(int, int),所以执行SlowPoint里的方法,而不是Point的原方法。

总结

JLS 15.12.1和方法重写的运行时行为并不矛盾:前者管「编译时能不能找到合法的方法签名」,后者管「运行时到底执行哪个类的方法」。你之前只看了编译阶段的规则,忽略了运行时的方法选择逻辑,所以才产生了困惑。

内容的提问来源于stack exchange,提问作者user24723440

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 20:03:20