Java父类构造器调用子类重写方法的实用解决方案咨询
解决方案:实现子类初始化完成后自动执行父类定义的重写方法
问题本质
该问题的根源是JVM固定的类初始化顺序:
- 父类静态资源初始化
- 子类静态资源初始化
- 父类实例成员初始化
- 父类构造方法执行
- 子类实例成员初始化
- 子类构造方法执行
父类构造执行时子类的自定义赋值逻辑还未运行,此时调用子类重写的方法必然会拿到未初始化的成员变量值。
方案1:静态工厂方法(纯Java原生,无第三方依赖)
这是最通用的解决方案,通过统一的实例创建入口,保证实例完全初始化完成后再调用目标方法:
import java.util.function.Supplier; public abstract class Parent { // 构造器设为protected,禁止外部直接new父类/子类实例 protected Parent() {} // 要求子类实现的抽象方法 protected abstract void print(); // 全局统一的实例创建工厂 public static <T extends Parent> T createInstance(Supplier<T> supplier) { T instance = supplier.get(); // 实例完全初始化完成后再调用重写方法 instance.print(); return instance; } }
子类实现:
public class Child extends Parent { private int i; // 构造器同样设为protected,强制走工厂方法创建实例 protected Child(int i) { super(); this.i = i; } @Override protected void print() { System.out.println("代码正常运行,i = " + i); } }
调用方式:
Child child = Parent.createInstance(() -> new Child(10));
该方案完全基于原生Java实现,强制约束所有实例创建逻辑,不会出现漏调用的问题。
方案2:@PostConstruct注解(IoC容器场景)
如果项目使用Spring等IoC容器管理Bean,可以直接用容器提供的初始化回调能力,代码侵入性极低:
import javax.annotation.PostConstruct; public abstract class Parent { // 容器会在Bean完全初始化后自动调用该方法 @PostConstruct protected void initAfterConstruct() { print(); } protected abstract void print(); }
子类只需正常实现抽象方法即可,无需额外编写调用逻辑:
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class Child extends Parent { @Value("${business.config.i:20}") private int i; @Override protected void print() { System.out.println("容器初始化完成后执行,i = " + i); } }
注意事项
- 两种方案都建议将重写方法的权限设为
protected,避免外部随意调用破坏初始化逻辑 - 工厂方法方案需要团队统一约定所有子类实例都通过父类工厂方法创建,禁止直接new子类实例,否则会出现初始化方法未执行的问题
内容的提问来源于stack exchange,提问作者Hizzie
相关产品推荐
相关产品推荐

