为什么我不能在子类构造函数中添加额外的参数验证?

Why can't I add extra argument validation in the subclass constructor?

我有两个类。超类:

public abstract class Question(){

public Question(String question, String answer, String... alts){...
}

和子类:

public class StringOptionsQuestion extends Question {

public StringOptionsQuestion(String question, String answer, String... alts){
    if (alts.length == 0){throw new IllegalArgumentException();} //The compiler doesn't like this line.
    super(question, answer, alts);
}}

我希望我的子类 StringOptionsQuestion 在将 alts 的长度传递给超类的构造函数之前验证它的长度。但是,我不能这样做。我收到错误 "Constructor call must be the first statement in a constructor"。为什么会出现这个错误?在我的案例中如何绕过它?

super() 语句 必须 是构造函数中的第一个:

super(question, answer, alts);
if (alts.length == 0) { 
    throw new IllegalArgumentException();
}

正如 kocko 指出的那样,super 语句必须是构造函数中的第一个 语句。但是,如果您真的、真的不想在验证之前达到超构造函数那么远(例如,因为它会因一个不太有用的错误而爆炸),您可以在评估超构造函数的参数时进行验证:

public class StringOptionsQuestion extends Question {

    public StringOptionsQuestion(String question, String answer, String... alts) {
        super(question, answer, validateAlternatives(alts));
    }

    private static String[] validateAlternatives(String[] alternatives) {
        if (alternatives.length == 0) { 
           throw new IllegalArgumentException();
        }
        return alternatives;
    }
}

正如其他人所说,对 super(...) 的调用必须 是子类构造函数中的第一条语句。

但是,它不一定是要计算的第一个 表达式

如果你真的需要在调用超类构造函数之前做一些事情(这不是标准代码——如果你是的话,你应该真正记录你为什么这样做)然后你可以通过调用一个静态方法作为表达式来做这样的事情:

public class StringOptionsQuestion extends Question {

    private static String[] checkAlts(String[] alts) {
        if (alts.length == 0) {
            throw new IllegalArgumentException();
        }
        return alts;
    }

    public StringOptionsQuestion(String question, String answer, String... alts) {
        super(question, answer, checkAlts(alts));
    }
}

超级class 构造函数将始终被调用。要么你明确地调用它,要么 java 为你做。当您从 subclass 构造函数中显式执行此操作时,它必须是构造函数中的第一件事。

我不确定您的具体要求是什么,但我的猜测是您想避免在 StringOptionsQuestion subclass if alts.length == 0 的情况下构造对象。您可以通过在你的 super class 中添加另一个构造函数来实现这一点,它需要一个额外的布尔参数,比如 'checkLength' 并且如果它的值是 true 验证长度并在需要时抛出异常。然后从您的 StringOptionsQuestion subclass 调用新的构造函数。

public 摘要 class 问题(){

public 问题(字符串问题,字符串答案,字符串...替代){... }

public 问题(字符串问题,字符串答案,字符串...替代,布尔检查长度){

if (checkLength && alts.length == 0){抛出新的 IllegalArgumentException();}

}

}

public class StringOptionsQuestion 扩展问题 {

public StringOptionsQuestion(字符串问题,字符串答案,字符串...替代){

super(question, answer, alts, true);

}}