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