彻底明白JAVA的异常处理 -3

类别:Java 点击:0 评论:0 推荐:

四.继承中异常

1.         关于构造函数中的异常

1.1          构造函数中的异常规则

某个derived class构造函数的“异常规格接口“可以比其所调用的父类的构造函数的异常规格接口宽,但决不能变窄。

1)        derived class的构造函数必须在自己的异常规格中声明所有base class构造函数的异常规格中所声明的异常。

2)        在derived class的构造函数的异常规格中还可以声明新的异常,即声明在base class构造函数的异常规格中没有声明的异常。

1.2          原因

当在产生一个derived class的对象时,会在derived class的构造函数中调用base class的构造函数(初始化过程请见第6章),所以在derived class的构造函数中可能会抛出base class构造函数的异常规格中声明的异常,因此要在derived class的异常规格中声明base class构造函数的异常规格中声明的异常。

**:如果调用的函数的异常规格中声明了异常,那么在调用该函数的时候要捕捉它的异常规格中声明的异常。但在derived class构造函数中却无法捕捉其base class构造函数所掷出的异常。

2.         关于非构造函数的异常规则

2.1          某个函数的“异常规格接口“在继承和重载中可以变窄,但决不能变宽

要覆写base class的函数时,如果被覆写函数(base class中的函数)的异常规格中声明了异常,那么覆写函数(derived class中覆写了base class中的函数的那个函数)的异常规格中可以声明(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)。由于BaseClass class中的被覆写f()函数没有声明异常规格,而代码(1)中覆写f()函数声明了,那么Test class中的f(BaseClass bc)虽然能处理被覆写f()函数的调用,但不能处理覆写f()函数的调用,因为代码覆写f()函数声明了异常规格,而f(BaseClass bc)没有进行捕捉。那么为了处理覆写f()函数,我们还要编写代码(3)那样的处理函数。

2.3          产生对象的异常规则

在产生一个对象时,捕捉的是产生对象时所调用的构造函数中所声明的异常。

2.4          函数调用时的异常规则

1)        当把一个对象向上转型为它的base class时,并通过转型后的reference进行函数调用时,我们要捕捉的是其base class的异常声明。

2)        当用对象的原始类型来调用函数时,只需捕捉所调用的覆写函数的异常

2.5          继承中的异常规则的一个实例

import java.lang.Exception;

class BaseException extends Exception {}

class Derived1Exception extends BaseException {}

class Derived2Exception extends BaseException {}

class Derived11Exception extends Derived1Exception {}

class BaseClass{

    BaseClass() throws Derived1Exception {}

    BaseClass(int i) throws BaseException {}

    BaseClass(int i, int j) {}

    //在覆写f()时不能声明异常规格

    public void f() {}

//在覆写g()时可以不声明异常或声明BaseException异常或声明

//BaseException异常的子类

    public void g() throws BaseException {}

    //在覆写u()时可以不声明异常

    public void u() throws Derived1Exception, Derived2Exception {}

}

class DerivedClass1 extends BaseClass{

    //base class构造函数中声明了异常的处理方法

    //声明与base class构造函数中的异常完全相同的异常

    DerivedClass1(int i) throws Derived1Exception {}

    //声明base class构造函数中的异常的父类异常

    DerivedClass1() throws BaseException {}   

    //声明base class构造函数中的异常和新的异常

    DerivedClass1(String s) throws Derived1Exception,  Derived2Exception{}

    //声明base class构造函数中的异常父类异常和新的异常

    DerivedClass1(String s, int i) throws BaseException,  Derived2Exception{}

    DerivedClass1(int i, int j) { super(i, j); }

    //注意下面这两句

    DerivedClass1(int i, String s) throws BaseException { super(i); }

    //!DerivedClass1(int i, String s) throws Derived1Exception { super(i);}

    public void f() {}

    //下面覆写g()的几种方式

    //不声明

    //public void g() {}

    //public void g() throws BaseException {} 声明完全相同

    //声明子类异常

public void g() throws Derived1Exception {}

//声明子类异常

    //public void g() throws Derived1Exception, Derived11Exception {} 

    //下面覆写u()的几种方式

    //public void u() {} 不声明

    //public void u() throws Derived11Exception {} 声明部分异常的异常

    //public void u() throws Derived1Exception {} 声明部分异常

    //声明完全相同

//public void u() throws Derived1Exception, Derived2Exception {} 

//声明子类异常

    //public void u() throws Derived1Exception, Derived11Exception {} 

}

public class Test{

    public static void main(String[] args){

        //捕捉的是相应的构造函数的异常

        try{

            BaseClass bc1 = new DerivedClass1();

        }

        catch(BaseException be) {}

        try{

            BaseClass bc2 = new DerivedClass1("bc2");

        }

        catch(Derived1Exception be1) {}

        catch(Derived2Exception be2) {}

        //通过向上转型来调用函数

        BaseClass bc3 = new DerivedClass1(1, 1);

        /*捕捉的是父类中被覆写的函数的异常,而这里捕捉的是子类中

         * 被覆写的函数的异常,所以编译错误

        try{

            bc3.g();

        }

        catch(Derived1Exception be) {}

        */

        //捕捉了被覆写函数的异常,是正确的

        try{

            bc3.g();

        }

        catch(BaseException be) {}

        //用对象的原始类型来调用函数

        DerivedClass1 dc1 = new DerivedClass1(1, 1);

        //只需捕捉所调用的覆写函数的异常

        try{

            dc1.g();

        }

        catch(Derived1Exception be) {}

    }

}

本文地址:http://com.8s8s.com/it/it16970.htm