使用Java构造函数抛出异常从类中进行子类化

时间:2015-02-23 16:23:25

标签: java exception constructor

我的理解是,子类中的重写方法不应该在父类的基本方法上抛出异常或更窄的异常。为什么它在构造函数中起反作用,子类的构造函数必须抛出相同的异常或更广泛,对此有任何合理的解释?

class MyException extends Exception{}
class MySubException extends MyException{}
class MySubSubException extends MySubException{}

public class Alpha {

  public Alpha() throws MyException{

  }
  void foo() throws MyException {}
}

class Beta extends Alpha{

 public Beta() throws MyException{ //NOT MySubSubException
    super();
 }

 void foo() throws MySubException {} //Ok for methods
}

3 个答案:

答案 0 :(得分:5)

  

为什么它在构造函数中起反作用,构造函数是构造函数   子类必须抛出相同的异常或更广泛,任何合理的   对此有何解释?

子类构造函数始终通过调用super(..)来调用其父构造函数。在这种情况下,父构造函数被声明为抛出类型为MyException的已检查异常。您的子类构造函数必须能够处理它(使用throws,因为super(..)必须是构造函数体中的第一个语句。)

使用方法,您不必强制调用super实现。

答案 1 :(得分:1)

方法的声明例外是其公共合同的一部分。声明的异常是方法可能抛出的异常,但它们必须抛出该方法的情况并非如此。覆盖方法不需要与它们覆盖的方法具有完全相同的签名;他们可以限制签名。

考虑以下示例:

class A { 
    A f() throws MyException { ... }
}
class B {
    @Override
    B f() throws MySubException { ... }
}
class C {
    void g(A a) {
        ...
    }
}

此处,类f的方法B会覆盖类f的方法A,尽管它没有完全相同的签名。但B的所有实例都符合A的约定,因为方法B.f确实返回A实例,并且除非它是{的子类,否则不能抛出已检查的异常{1}}。因此,我们可以安全地将MyException实例传递给任何要求B引用的方法,例如A类中的g(A a)

对于构造函数而言,情况并非如此。首先,构造函数不属于实例,它们属于,构造函数永远不会覆盖另一个构造函数。但它们总是(隐式或显式地)调用超类的构造函数。当此构造函数声明已检查的异常时,构造函数必须使用C块处理它们,或者自己声明它们。

答案 2 :(得分:0)

注意@Hoopje,当使用super()调用超类的构造函数时,你无法在try {} catch中捕获异常,你必须在子类构造函数中声明throws。