抽象类通过仅提供带参构造器强制子类传入必要参数,并在构造器中校验非空与有效性、初始化final字段,同时用protected final字段或getter供子类安全访问,严禁在构造器中调用抽象方法。

抽象类本身不能被实例化,但它可以定义构造函数,并在子类构造过程中强制要求传入关键参数——这不是靠“拦截调用”,而是利用 Java 构造器链的语义规则:子类构造器必须显式或隐式调用父类构造器;若抽象父类只提供带参构造器,子类就无法绕过参数传递。
让子类必须传参:删掉无参构造器
只要抽象类不提供默认(无参)构造器,子类的构造器就必须通过 super(...) 显式调用父类带参构造器,否则编译失败。
- 抽象类中只声明一个含核心组件参数的构造器,例如:
protected AbstractProcessor(DataSource dataSource, Config config) { ... } - 子类构造器第一行必须写 super(dataSource, config);,否则报错:“Implicit super constructor AbstractProcessor() is undefined”
- 这样,dataSource 和 config 就成了子类初始化时不可省略的依赖
在构造器里做校验,守住初始化底线
抽象类构造器不只是收参数,更是执行初始化契约的第一道关卡。
- 对传入的核心组件做非空、状态有效性等检查,例如:
if (dataSource == null) throw new IllegalArgumentException("dataSource is required"); - 可初始化 final 字段(如 private final DataSource ds;),确保后续所有子类实例都持有合法、不可变的依赖
- 避免把校验逻辑放到模板方法或抽象方法里——构造期就该拦住问题,而不是等到 process() 才抛异常
配合 protected 成员,让子类安全使用这些组件
传进来的核心组件不应直接暴露为 public,而应通过受控方式供子类访问。
立即学习“Java免费学习笔记(深入)”;
- 将关键字段声明为 protected final DataSource dataSource;,子类可直接读取,但无法替换
- 或提供 protected DataSource getDataSource() { return this.dataSource; },便于未来加日志、代理等扩展
- 禁止声明为 public 或 private:前者破坏封装,后者子类无法使用
常见误区:别在构造器里调用抽象方法
这是危险操作——子类对象尚未完成初始化,此时调用子类重写的抽象方法,可能导致字段为 null 或逻辑错乱。
- 例如在抽象构造器中写 this.init();(而 init() 是 abstract),JVM 会调用子类版本,但子类字段可能还未赋值
- 正确做法是把运行时才需定制的行为留在模板方法中(如 execute() 调用 doWork()),构造器只负责“把东西接进来、验好、存稳”


















