关于类之间方法调用层级的理解困惑及代码咨询
解析Java类的构造执行顺序与方法调用逻辑
首先先把完整的测试代码补全(你的Main类代码不完整,我补充了常见的测试场景):
class X { protected int v = 0; public X() { v = v + 10; } public void proc(X p) { System.out.println(43); } } class Y extends X { public Y() { v = v + 5; } public void proc(X p) { System.out.println(57); } public int getV() { return v; } } class Z extends Y { public Z() { v = v + 9; } public void proc(Z p) { System.out.println(39); } } class Main { public static void main(String[] args) { // 测试构造函数与v的值 Z z = new Z(); System.out.println(z.getV()); // 输出24 // 测试方法调用1 X x1 = new Z(); x1.proc(new X()); // 输出57 // 测试方法调用2 Z z2 = new Z(); z2.proc(new Z()); // 输出39 // 测试方法调用3 Z z3 = new Z(); z3.proc(new Y()); // 输出57 } }
接下来分两部分拆解你可能困惑的点:
一、构造函数的执行顺序与v值计算
Java中,子类构造函数会默认先调用父类的无参构造,这个过程是链式的:
- 创建
Z实例时,首先执行父类Y的构造,而Y又会先执行父类X的构造; X的构造:初始v=0,执行v = v +10后,v=10;Y的构造:接着执行v = v +5,v=10+5=15;Z的构造:最后执行v = v +9,v=15+9=24;
所以调用getV()会返回24。
二、方法调用的匹配逻辑(重载+重写)
这里核心要区分编译时的重载解析和运行时的多态(重写):
1. 重写(Override)的规则
Y类的proc(X p)重写了X类的同名同参数方法,所以当一个对象的实际类型是Y或其子类(比如Z),且调用的是proc(X)方法时,会执行Y类的实现(输出57),而不是X的(输出43)。Z类的proc(Z p)并不是重写,而是重载(参数类型不同),它和父类的proc(X p)是两个不同的方法。
2. 不同场景下的方法调用
场景1:
X x1 = new Z(); x1.proc(new X());- 编译时:变量
x1的编译类型是X,所以编译器只会找X类中定义的方法,也就是proc(X p); - 运行时:对象的实际类型是
Z,但Z没有重写proc(X p),所以会往上找最近的重写实现——也就是Y类的proc(X p),最终输出57。
- 编译时:变量
场景2:
Z z2 = new Z(); z2.proc(new Z());- 编译时:变量
z2的编译类型是Z,编译器会优先匹配最精确的参数类型——Z类中定义的proc(Z p); - 运行时直接执行这个方法,输出39。
- 编译时:变量
场景3:
Z z3 = new Z(); z3.proc(new Y());- 编译时:
Y是X的子类,没有匹配到proc(Y p),所以会匹配父类中参数类型为X的proc(X p); - 运行时:实际类型是
Z,但Z没重写proc(X p),所以执行Y类的实现,输出57。
- 编译时:
内容的提问来源于stack exchange,提问作者Laurențiu Boran
相关产品推荐
相关产品推荐

