最根本、最安全的做法是避免在父类构造函数中调用可能被子类重写的方法,因为此时子类对象尚未初始化,调用重写方法会导致访问未赋值字段或空指针异常;应仅调用private或final方法,或延后至init()、工厂方法中执行。

直接避免在父类构造函数中调用任何可能被子类重写的方法,是最根本、最安全的做法。
为什么这是高危操作
父类构造函数执行时,子类对象尚未完成初始化——字段还未赋值、子类构造逻辑还没运行。此时若调用被子类重写的方法,该方法会以“半初始化”的子类实例为上下文执行,极易访问到未初始化的字段或触发空指针异常。这不是设计缺陷,而是 Java 初始化顺序与多态动态绑定共同作用下的必然结果。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
具体规避策略
- 构造函数内只调用 private 或 final 方法:这两类方法无法被子类重写,能确保调用的是父类自身定义的行为,完全避开多态干扰。
-
把初始化逻辑拆出来,延后执行:例如提供一个
init()方法,由创建者在对象构造完成后显式调用;或使用工厂方法封装构造 + 初始化全过程。 - 用静态工厂替代 public 构造器:在工厂方法中先 new 出对象,再调用安全的初始化方法,控制权更清晰,也便于做参数校验和状态检查。
-
必要时用模板方法模式,但需谨慎设计钩子:如果必须预留扩展点,父类应定义
final的构造流程,在其中调用protected abstract模板方法——但该抽象方法本身不能在构造函数中直接调用,而应在构造完成后的某个明确阶段触发。
识别风险代码的信号
看到父类构造函数里出现以下任一情况,就要警惕:
- 调用了非 private、非 final 的实例方法;
- 方法名看起来像业务逻辑(如
loadConfig()、validate()、setup())而非纯工具方法; - 该方法在子类中已存在重写实现,或已有子类继承该父类。
补充提醒
IDE(如 IntelliJ)通常会对这类调用给出警告提示,比如 “Call to potentially overridden method in constructor”。别忽略它——这不是建议,是编译器在帮你提前拦截运行时隐患。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










