在调用超类构造函数方法之前检查子类中的条件

时间:2016-07-14 18:00:41

标签: java inheritance constructor

正如我们在子类的构造函数体中所知,父构造函数必须是第一个语句,否则我们会得到编译时错误。本主题已经讨论过here

假设调用父构造函数导致系统资源成本高昂,另一方面在子类构造函数中我们需要首先检查一些条件如果满足条件我们通过父构造函数很好,那么就没有必要更进一步了(让我们说抛出异常):

class parent {
    parent(Object blah) {
        //Heavy resource consuming tasks
    }
}

class child extends parent {
    child(Object blah, boolean condition) {
        if (!condition) throw new IllegalArgumentException("Condition not satisfied");
        super(blah); //Compile error!
    }
}

如果有人遇到同样的问题,我很奇怪无论如何都要处理这种情况,或者我必须首先调用父构造函数,无论浪费多少资源然后抛出异常?

2 个答案:

答案 0 :(得分:10)

你可以这样做:

public class Jlaj extends ArrayList<String> {

    public Jlaj(int capacity) {
        super(checkCapacity(capacity));
    }

    private static int checkCapacity(int capacity) {
        if (capacity > 1000)
            throw new IllegalArgumentException();
        return capacity;
    }

    public static void main(String[] args) {
        new Jlaj(1001); // this throws IAE all right
    }
}

请注意,您只能以这种方式调用静态方法,这很好:在部分初始化的对象上调用实例方法已经是一个巨大的麻烦,甚至在超类构造函数成为噩梦之前调用它们。

现在如果你需要检查一些你没有传递给超类的其他参数呢?你可以这样做:

public class Jlaj extends ArrayList<String> {

    private final Object foo;

    public Jlaj(int capacity, Object foo) {
        super(checkArgumentsAndReturnCapacity(capacity, foo));
        this.foo = foo;
    }

    private static int checkArgumentsAndReturnCapacity(int capacity, Object foo) {
        if (capacity > 1000)
            throw new IllegalArgumentException();
        if (foo == null)
            throw new NullPointerException();
        return capacity;
    }

    public static void main(String[] args) {
        new Jlaj(1000, null); // throws NPE
    }
}

它有效,但看起来有点难看。你将两个不相关的东西传递给一个只返回超类参数的函数。至少描述性名称在某种程度上弥补了这一点。

答案 1 :(得分:3)

如果您绝对需要这样做,可以使用私有构造函数创建静态构建器方法:

class child extends parent {
    private child(Object blah) {
        super(blah);
    }

    static child create(Object blah, boolean condition) {
        if (!condition) throw new IllegalArgumentException("Condition not satisfied");

        return new child(blah);
    }


    public static void main(String[] args) {
        child a = child.create("a", true);
    }
}

我不是单独的init方法的粉丝,因为如果你忘了打电话,你最终会得到无效状态。