Java子类重写方法的参数传递与执行副作用问题解析
解析Java子类方法调用中的参数传递与执行逻辑
咱们一步一步拆解这段代码的执行过程,就能搞清楚参数怎么传递、方法调用的逻辑,还有为啥最后输出是0了。
一、子类B的setX方法参数传递路径
当执行new B()创建对象时,参数的传递是这样走的:
- 首先进入父类A的构造器,构造器里的
setX(x-3)中,这里的x是父类A的实例变量,初始值是3,所以计算得出3-3=0,这个0就是要传递的参数。 - 由于Java的动态绑定机制(多态),此时实际创建的是B对象,所以会调用子类B重写的
setX方法,这个0就被传递给了B的setX方法的参数z。
二、完整的方法调用执行逻辑
按代码执行的先后顺序梳理:
- 第一步:执行
A ab = new B();,触发B的实例化。Java规定子类构造器默认会先调用父类的无参构造器,所以先进入A的构造方法。 - 第二步:在A的构造器中执行
setX(x-3):- 这里的
x是A类的实例变量,值为3,计算后得到参数值0。 - 因为当前对象的实际类型是B,所以调用的是B类中重写的setX方法,而不是A自己的setX方法。
- 这里的
- 第三步:进入B的
setX(int z)方法:- 参数
z接收的就是从父类构造器传过来的0。 - 方法里的
x = z,这里的x是B类的静态变量(B类定义的是static int x=7),所以直接把B的静态x的值改成了0。
- 参数
- 第四步:父类构造器执行完成后,回到B的默认构造器(B没有显式写构造器,所以用默认的空构造),对象创建完成。
- 第五步:执行
System.out.println(B.x),输出的是B类的静态变量x,此时它的值已经被改成0,所以最终输出0。
三、执行过程中的副作用与注意点
- 父类构造调用子类重写方法的风险:这是Java里一个容易踩坑的点!父类构造器执行时,子类的实例初始化还没完成(如果子类有实例变量的话),此时调用子类重写的方法,可能会访问到未初始化的子类实例变量,导致奇怪的错误。这里还好是修改静态变量,但依然属于意外修改了子类的状态。
- 变量命名混淆的坑:这里A的
x是实例变量,B的x是静态变量,两者是完全独立的变量。新手很容易把它们搞混,误以为是同一个变量被修改,其实是两个不同的东西。 - 静态变量的全局影响:B的静态变量x属于类本身,所有B的对象都会共享这个值,这次父类构造器的调用直接修改了这个全局静态值,导致后续所有访问B.x的地方都会拿到修改后的值。
内容的提问来源于stack exchange,提问作者Karl
相关产品推荐
相关产品推荐

