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
相关产品推荐
相关产品推荐

