You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 21中构造器调用super(...)前避免空引用的可行方案

可行的解决方案

针对你遇到的问题,有两种比较优雅的Java实现方案,既满足参数校验抛自定义异常的需求,又不用破坏父类的设计或写繁琐的逻辑:

方案一:用静态工厂方法替代拷贝构造器

这是最推荐的方案,完全绕开了构造器必须先调用super()的限制,把参数校验逻辑放在工厂方法里,再安全地调用构造器。

代码示例:

// 抽象父类
public abstract class MySuperClass {
    private final String mySuperField;

    protected MySuperClass(String mySuperField) {
        this.mySuperField = mySuperField;
    }

    public String getMySuperField() {
        return mySuperField;
    }
}

// 子类
public class MySubClass extends MySuperClass {
    private final String mySubField;

    // 私有构造器,仅内部工厂方法调用
    private MySubClass(String superField, String subField) {
        super(superField);
        this.mySubField = subField;
    }

    // 对外暴露的拷贝方法(静态工厂)
    public static MySubClass copyOf(MySubClass toCopy) {
        // 先做参数校验,抛自定义异常
        if (toCopy == null) {
            throw new CustomNullPointerException("拷贝对象不能为null");
        }
        // 校验通过后再创建实例
        return new MySubClass(toCopy.getMySuperField(), toCopy.getMySubField());
    }

    public String getMySubField() {
        return mySubField;
    }
}

优点:

  • 逻辑清晰,校验和实例创建分离,符合单一职责
  • 可以隐藏构造器,控制子类实例的创建逻辑(比如后续加缓存、返回子类的子类实例等)
  • 不用修改父类的任何代码,对现有结构侵入性小

方案二:父类/工具类提供静态校验+字段提取方法

如果必须保留拷贝构造器的形式,可以把校验逻辑封装成静态方法,放在super()的参数中调用——因为Java允许构造器的第一行super()的参数是方法调用,而方法会先执行,这样就能在进入父类构造器前完成校验。

代码示例:

// 抽象父类
public abstract class MySuperClass {
    private final String mySuperField;

    protected MySuperClass(String mySuperField) {
        this.mySuperField = mySuperField;
    }

    // 静态校验+提取父类字段的方法
    protected static String validateAndGetSuperField(MySuperClass source) {
        if (source == null) {
            throw new CustomNullPointerException("拷贝对象不能为null");
        }
        return source.getMySuperField();
    }

    public String getMySuperField() {
        return mySuperField;
    }
}

// 子类
public class MySubClass extends MySuperClass {
    private final String mySubField;

    public MySubClass(MySubClass toCopy) {
        // 先调用静态方法完成校验,再传入父类构造器
        super(validateAndGetSuperField(toCopy));
        // 这里可以继续处理子类字段的拷贝,此时toCopy一定非null
        this.mySubField = toCopy.getMySubField();
    }

    public String getMySubField() {
        return mySubField;
    }
}

优点:

  • 保留了拷贝构造器的形式,符合部分开发者的使用习惯
  • 保持了父类字段的final特性,不破坏原有不可变设计

如果不能修改父类,也可以把静态校验方法放到一个独立的工具类里,比如CopyUtils.validateAndGetSuperField(toCopy),效果是一样的。

内容的提问来源于stack exchange,提问作者Amateur Linguist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 16:40:11