Java类继承中编译器如何确定调用的方法?代码示例疑问
Java方法调用的重载与动态绑定问题
class All { /* ... */ } class Most extends All { /* ... */ } class Special extends Most { /* ... */ } class Top { public void m( All p ) { System.out.print("A "); } } class Middle extends Top { public void m( All p ) { System.out.print("M "); } public void m( Special p ) { System.out.print("L "); } } class Bottom extends Middle { public void m( Most p ) { System.out.print("V "); } public void m( Special p ) { System.out.print("X "); } } class Test { public static void run() { All all = new All(); Most most = new Most(); Special special = new Special(); Top x = new Middle(); Top y = new Bottom(); Middle z = new Bottom(); x.m( most ); x.m( special ); y.m( all ); y.m( special ); z.m( all ); z.m( most ); } }
这段代码运行后输出为 M M M M M M,以下是对相关疑问的解答:
疑问与解答
1. 为何编译器总是调用Middle类的m()方法?
要搞清楚这个问题,得拆分编译期重载解析和运行期动态绑定两个阶段:
- 编译阶段:编译器只看变量的声明类型来筛选可选方法。比如
x声明为Top,Top里只有m(All)这一个方法,所以不管传入Most还是Special(它们都是All的子类,可向上转型),编译器都会把调用绑定到m(All)这个方法签名上。 - 运行阶段:JVM根据对象的实际类型调用重写的方法。
x实际是Middle,Middle重写了m(All);y实际是Bottom,但Bottom没重写m(All),会继承Middle的实现,最终都会调用Middle的m(All)。
2. 为什么x.m(special)不输出L?
x的声明类型是Top,编译时编译器只能看到Top类里的方法,看不到Middle中新增的m(Special)重载方法。它会在Top的方法列表里找能接收Special参数的方法,最终匹配到m(All)(因为Special是All的子类)。到了运行阶段,方法签名已经被编译成m(All),所以只会执行Middle中重写的m(All),输出M而非L。
3. y.m(all)和y.m(special)为何都输出M?
y.m(all):y声明为Top,编译时匹配m(All);运行时y实际是Bottom,但Bottom没有重写m(All),会继承Middle的m(All)实现,输出M。y.m(special):和上面逻辑一致,编译时Top只有m(All)能接收Special参数,方法签名确定为m(All);运行时还是调用Middle的m(All),输出M。
内容的提问来源于stack exchange,提问作者Niklas S
相关产品推荐
相关产品推荐

