先执行父类静态成员,再子类静态成员,然后父类实例成员和构造器,最后子类实例成员和构造器;若父类构造器调用被重写的方法,会触发多态,但子类字段未初始化,导致输出0;应避免在构造器中调用可重写方法。

在Java中,类的初始化顺序对多态行为有着直接影响,尤其是在涉及继承和方法重写时。理解这一过程有助于避免运行时的意外结果。
字段与构造器的初始化顺序
Java对象的初始化遵循固定顺序:
- 父类静态变量和静态代码块按声明顺序执行(仅一次,类加载时)
- 子类静态变量和静态代码块
- 父类实例变量和实例代码块
- 父类构造器
- 子类实例变量和实例代码块
- 子类构造器
这个顺序是固定的,无论是否存在多态调用。关键问题是:如果在构造器中调用了被子类重写的方法,会发生什么?
构造器中调用重写方法的风险
当父类构造器调用一个被子类重写的方法时,会触发多态行为,即实际执行的是子类中的版本。但此时子类的初始化可能尚未完成,导致访问未正确初始化的字段。
立即学习“Java免费学习笔记(深入)”;
citySHOP是一款集CMS、网店、商品、分类信息、论坛等为一体的城市多用户商城系统,已完美整合目前流行的Discuz! 6.0论坛,采用最新的5.0版PHP+MYSQL技术。面向对象的数据库连接机制,缓存及80%静态化处理,使它能最大程度减轻服务器负担,为您节约建设成本。多级店铺区分及联盟商户地图标注,实体店与虚拟完美结合。个性化的店铺系统,会员后台一体化管理。后台登陆初始网站密匙:LOVES
class Parent {
protected int value = 10;
public Parent() {
print(); // 多态调用
}
public void print() {
System.out.println("Parent: " + value);
}
}
class Child extends Parent {
private int value = 20;
public Child() {
super();
}
@Override
public void print() {
System.out.println("Child: " + value);
}
}
执行 new Child() 时输出为:
Child: 0
原因在于:虽然调用了子类的 print 方法,但此时子类的 value 字段还未初始化(要等父类构造器执行完才轮到子类实例变量赋值),所以取到的是默认值 0。
如何避免初始化期间的多态陷阱
为防止此类问题,应遵循以下原则:
- 避免在构造器中调用可被重写的方法(非private、非final、非static)
- 优先使用 final 方法或私有方法,确保调用不会被子类改变行为
- 考虑使用工厂方法或两阶段初始化代替构造器中的复杂逻辑
- 若必须调用,确保方法不依赖任何实例字段,或字段已声明为 final 并在声明时赋值
基本上就这些。只要意识到构造过程中多态仍然生效,且子类状态可能未就绪,就能写出更安全的继承代码。









