为什么Java对象运行时类型在部分方法调用场景生效部分不生效?
核心原因
这是Java语言方法分派的固定规则导致的,本质是**重载(Overload)是静态分派(编译期确定)、重写(Override)是动态分派(运行期确定)**的差异:
分派规则细节
- 编译期静态分派:只根据「调用对象的声明类型」+「方法参数的声明类型」确定要调用的方法签名,参数的实际运行时类型完全不参与这一步判断,这一步会选定重载的具体版本。
- 运行期动态分派:只根据「调用方法的对象的实际运行时类型」,匹配对应重写的方法版本,参数的实际类型同样不参与这一步判断。
逐行分析代码运行逻辑
代码运行后输出顺序及对应逻辑如下:
- 第一段调用
baseObject.selectMethod(subscribeAsBase)- 编译期:参数
subscribeAsBase的声明类型是BaseClass,所以选定重载版本为selectMethod(BaseClass x) - 运行期:调用对象
baseObject的实际类型是BaseClass,所以执行BaseClass中定义的selectMethod(BaseClass x),输出:BaseClass.selectMethod(BaseClass 'A Subclass object')
subscribeAsBase的实际运行时类型是SubClass,也不会影响编译期已经选定的重载版本,所以参数的运行时类型看起来没有生效。 - 编译期:参数
- 第二段调用
subscribeAsBase.selectMethod(subscribe)- 编译期:参数
subscribe的声明类型是SubClass,所以选定重载版本为selectMethod(SubClass x) - 运行期:调用对象
subscribeAsBase的实际类型是SubClass,SubClass重写了selectMethod(SubClass x)方法,所以执行SubClass中的对应方法,输出:SubClass.selectMethod(SubClass 'A Subclass object')
- 编译期:参数
补充验证
如果要让第一段调用也匹配SubClass参数的重载版本,可以手动强制转换参数的声明类型,修改为:
baseObject.selectMethod((SubClass) subscribeAsBase);
此时编译期会将参数的声明类型识别为SubClass,选定selectMethod(SubClass x)重载版本,运行时执行BaseClass的对应方法,输出:
BaseClass.selectMethod(SubClass 'A Subclass object')
内容的提问来源于stack exchange,提问作者Agent smith 2.0
相关产品推荐
相关产品推荐

