[摘要]四. 继承中异常 1. 关于构造函数中的异常 1.1 构造函数中的异常规则 某个derivedclass构造函数的“异常规格接口“可以比其所调用的父类的构造函数的异常规格接口宽,但决不能变窄。 1) derivedclass的构造函数必须在自己的异常规格中声明所有basecl...
四. 继承中异常
1. 关于构造函数中的异常
1.1 构造函数中的异常规则
某个derivedclass构造函数的“异常规格接口“可以比其所调用的父类的构造函数的异常规格接口宽,但决不能变窄。
1) derivedclass的构造函数必须在自己的异常规格中声明所有baseclass构造函数的异常规格中所声明的异常。
2) 在derivedclass的构造函数的异常规格中还可以声明新的异常,即声明在baseclass构造函数的异常规格中没有声明的异常。
1.2 原因
当在产生一个derivedclass的对象时,会在derivedclass的构造函数中调用baseclass的构造函数(初始化过程请见第6章),所以在derivedclass的构造函数中可能会抛出baseclass构造函数的异常规格中声明的异常,因此要在derivedclass的异常规格中声明baseclass构造函数的异常规格中声明的异常。
**:如果调用的函数的异常规格中声明了异常,那么在调用该函数的时候要捕捉它的异常规格中声明的异常。但在derivedclass构造函数中却无法捕捉其baseclass构造函数所掷出的异常。
2. 关于非构造函数的异常规则
2.1 某个函数的“异常规格接口“在继承和重载中可以变窄,但决不能变宽
要覆写baseclass的函数时,如果被覆写函数(baseclass中的函数)的异常规格中声明了异常,那么覆写函数(derivedclass中覆写了baseclass中的函数的那个函数)的异常规格中可以声明(1)与被覆写函数完全相同的异常;(2)被覆写函数异常规格中的部分异常或其子类异常;(3)不声明异常规格。
2.2 原因
这么做是为了满足“能处理被覆写函数的代码,不用做任何修改就能处理覆写函数的代码”的原则。
如果覆写函数的异常规格中声明了在被覆写函数的异常规格中不存在的异常,那么能处理被覆写函数的代码就不能处理覆写函数,因为没有捕捉覆写函数中不存在于被覆写函数中的异常声明。
import java.sql.SQLException;
class BaseClass{
public void f(){}
}
class DerivedClass1 extends BaseClass{
//public void f() throws SQLException {}(1)
public void f() {}//(2)
}
public class Test{
public static void f(BaseClass bc) { bc.f(); }
/*(3)
public static void f(BaseClass bc) {
try{
bc.f();
}
catch(SQLException ex){}
}
*/
public static void main(String[] args){
BaseClass bc = new BaseClass();
f(bc);
DerivedClass1 dc = new DerivedClass1();
f(bc);
}
}
如果允许“异常接口“变宽,我们看看上面代码会出现什么结果。首先,我们可以将代码(1)的注释去掉,并注释掉代码(2)。由于BaseClassclass中的被覆写f()函数没有声明异常规格,而代码(1)中覆写f()函数声明了,那么Testclass中的f(BaseClass bc)虽然能处理被覆写f()函数的调用,但不能处理覆写f()函数的调用,因为代码覆写f()函数声明了异常规格,而f(BaseClass bc)没有进行捕捉。那么为了处理覆写f()函数,我们还要编写代码(3)那样的处理函数。
2.3 产生对象的异常规则
在产生一个对象时,捕捉的是产生对象时所调用的构造函数中所声明的异常。
2.4 函数调用时的异常规则
1) 当把一个对象向上转型为它的baseclass时,并通过转型后的reference进行函数调用时,我们要捕捉的是其baseclass的异常声明。
2) 当用对象的原始类型来调用函数时,只需捕捉所调用的覆写函数的异常
……