Java实例化子类时父类构造调用print输出00的原因是什么?
Java继承构造调用重写方法问题解答
核心结论
- 父类构造方法中调用的
print()是子类Derived重写后的版本 - 输出
00是因为子类自定义的实例成员还未完成显式初始化,仍为int类型的默认值0
问题代码
public class Base { private int member1 = 1; private int member2 = 2; public Base() { System.out.println("base ctor"); print(); } public void print() { System.out.println(member1 + "" + member2); } } class Derived extends Base { private int member3 = 3; private int member4 = 4; public Derived() { System.out.println("derived ctor"); print(); } public void print() { System.out.println(member3 + "" + member4); } } class Test{ public static void main(String[] args) { Derived d = new Derived(); } }
实际运行输出
base ctor 00 derived ctor 34
原理说明
1. 方法调用的动态分派规则
Java的非私有实例方法采用动态分派机制,方法的实际执行版本由对象的运行时实际类型决定。本次代码中创建的是Derived类型的对象,所以所有对print()的调用默认都会执行子类重写的实现,哪怕该调用是写在父类的构造方法中。
同时父类的member1、member2是private修饰,子类无法直接访问,子类重写的print()方法操作的完全是自己定义的member3、member4两个成员,和父类的成员无关。
2. 继承类的实例化执行顺序
当创建子类对象时,JVM的执行流程严格按照以下顺序:
- 为整个子类对象分配内存空间,所有实例成员(包括父类继承的、子类自己定义的)全部初始化为对应数据类型的默认值,int类型的默认值为0,此时
member1=0,member2=0,member3=0,member4=0 - 进入子类构造方法,首先隐式调用父类构造方法:
- 先执行父类的实例成员显式初始化:
member1=1,member2=2 - 执行父类构造方法的代码:
- 打印
base ctor - 调用
print()方法,动态分派到子类实现,此时子类的member3、member4还没有进行显式初始化,仍然是默认值0,所以输出00
- 打印
- 先执行父类的实例成员显式初始化:
- 父类构造方法执行完毕,回到子类流程,执行子类的实例成员显式初始化:
member3=3,member4=4 - 执行子类构造方法的剩余代码:
- 打印
derived ctor - 调用
print()方法,此时子类成员已经完成赋值,输出34
- 打印
注意:在构造方法中调用可被重写的实例方法是非常危险的操作,很容易因为子类成员未完成初始化导致逻辑异常,实际开发中应当尽量避免这种写法。
内容的提问来源于stack exchange,提问作者NoobCoder
相关产品推荐
相关产品推荐

