处理Java中重写方法层次结构中的异常

时间:2012-12-17 11:39:55

标签: java exception

考虑Java类层次结构,例如:

abstract class Exp { public void generate(); }
class EffExp extends Exp {...}
clas PureExp extends Exp {...}
class NewExp extends EffExp {...}
etc, etc.

generateNewExp的实施已更改为IOException

public void generate() throws IOException {...}

generate的其他实现不执行任何IO,因此不需要抛出它。编译器抱怨并强制我声明类层次结构中的所有方法以抛出异常。这真的是前进的唯一途径吗?这似乎很有侵扰性。

我当然可以在NewExp内找到它发生的异常,但这并没有多大意义。异常应传播到顶部并停止程序执行。

这里更一般的问题是:如果你有一个相互覆盖的方法层次结构,那么它们是否都必须被声明为抛出相同的异常集?

7 个答案:

答案 0 :(得分:1)

记住一条规则: -

  • 您无法为覆盖的方法添加更多限制。限制可以是例如: - 添加新的Checked Exception,降低方法可见性。

所以,如果你必须(没有选择),让你的重写方法抛出一个Checked Exception(注意,你可以添加一个未经检查的Exception,但它没有任何意义),只需添加您重写的方法的throws子句中的异常。

因此,简单来说,overridden方法的签名应该与覆盖它的签名完全匹配。


现在这背后的简单推理是 - Polymorphism

在多态中,正如您所知,您可以拥有一个super type个子对象的引用点。所以,你可以: -

SupClass ref = new SubClass();
ref.method1();

现在,在检查是否存在method1时,编译器只关注引用类型。因此,它会检入SupClass,并相应地允许访问。

现在,想象一下,在运行时,当ref实际指向SubClass对象时,JVM发现method1抛出了一个新的异常,而{ {1}}。它会崩溃。这就是不允许的原因。

答案 1 :(得分:1)

假设场景类似于:

abstract class Exp { public void generate(); }
class EffExp extends Exp { public void generate throw IOException(....)....}
clas PureExp extends Exp {public void generate(....)....}

我们使用抽象类表示法,以便我们可以实现其他类而不必担心实际的实现。如果我们实际;实现变窄,即在某些情况下抛出异常并且不抛弃其他情况,那么它显然违反Java是强健的。所以你需要明确同步。对于所有方法。

虽然您可以通过抛出父“异常”来提高可见性。

答案 2 :(得分:1)

在抽象类中,您可以定义抛出java.lang.Exception

abstract class Exp { public abstract void generate() throws Exception; }

在派生类中,更具体地说明了你抛出的异常类型。

答案 3 :(得分:0)

考虑一下这个简单的假设代码,让我们假设......符合您的描述:

Exp ex = new NewExp(); 
try {
ex.generate(); //It should throw an exception, but has no such method signature. 
} catch(AnException e) { //Nope, not allowed.
 ...
}

答案 4 :(得分:0)

是否需要抛出已检查的异常。你能将它包装在运行时异常中吗?

public void generate() {
     try {
     ....
     } catch (IOException e ){
        RuntimeException re = new RuntimeException();
        re.initCause(e);
        throw re;
     }   
}

(没有检查这个是否有编译,但它应该给你一个总体思路

答案 5 :(得分:0)

如果要覆盖方法,则超类中的重写方法只能声明抛出该异常(已检查)或其超类。否则你将失去多态性,因此在Java中不允许

答案 6 :(得分:0)

  1. 我们不能在重写方法中引入新的已检查异常,但可以使用子检查异常或父类中处理的异常。     即使我们这样做,如果我们使用父引用引用子对象,那么编译器将强制捕获在父类方法中声明的异常,然后查看下面的示例:

    class Parent{
                public void method throws IOException{
                }
        } 
    
        class Child extends Parent{
               public void method throws SQLException{
               }      
        }
    
        class Test{
        public static void main(){
              Parent p=new Child();
    
             try{
              p.method();
             }catch(IOException e){
                e.printStackTrace();
             }
        }
    }
    

    在上面的程序中,子类方法抛出SQLException但Compiler将强制捕获IOException。因为在编译时编译器不知道子对象是从父引用引用的。 但是我们可以声明任何未经检查的异常,因为编译器不会为它们强制执行try / ctach或throws。