簡體   English   中英

處理Java中重寫方法層次結構中的異常

[英]Handling exceptions in a hierarchy of overridden methods in Java

考慮Java類層次結構,例如:

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

NewExp中的generate實現被更改為拋出IOException

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

generate的其他實現不執行任何IO,因此不需要拋出它。 編譯器抱怨並強制我聲明類層次結構中的所有方法以拋出異常。 這真的是前進的唯一途徑嗎? 這似乎是相當干擾的。

我當然可以在NewExp捕獲它發生的異常,但這並沒有多大意義。 異常應傳播到頂部並停止程序執行。

這里更一般的問題是:如果你有一個覆蓋彼此的方法層次結構,那么它們是否都必須被聲明為拋出相同的異常集?

記住一條規則 : -

  • 您無法為覆蓋的方法添加更多限制。 限制可以是例如: - 添加新的Checked Exception ,降低方法可見性。

所以,如果你必須(沒有選擇),讓你的重寫方法拋出一個Checked Exception (注意,你可以添加一個未經檢查的Exception,但它沒有任何意義),只需在throws子句中添加異常你重寫的方法。

因此,簡單來說, overridden方法的簽名應該與覆蓋它的方法完全匹配。


現在這背后的簡單推理是 - Polymorphism

在多態性中,如您所知,您可以擁有一個子類對象的super type引用點。 所以,你可以: -

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

現在,在檢查method1是否存在時,編譯器只關心引用類型。 因此,它檢查SupClass ,並允許相應的訪問。

現在,假設發生了什么,當在運行時,當ref實際指向SubClass對象時,JVM發現method1拋出一個新的異常, compiler沒有檢查過。 它會崩潰。 這就是為什么不允許這樣做的原因。

假設場景類似於:

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

我們使用抽象類表示法,以便我們可以實現我們的其他類而不必擔心實際的實現。 如果我們實際; 實現范圍縮小,即在某些情況下拋出異常並且不拋棄其他情況,那么它顯然違反Java是強健的。 所以你需要明確同步。 對於所有方法。

雖然您可以通過拋出父“異常”來提高可見性。

在抽象類中,您可以定義拋出java.lang.Exception

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

在派生類中,更具體地說明您拋出的異常類型。

只要考慮這個簡單的假設代碼,讓我們假設...符合您的描述:

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

是否需要拋出已檢查的異常。 你能把它包裝在運行時異常中嗎?

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

(沒有檢查這個編譯,但它應該給你一個大致的想法

如果要覆蓋方法,則超類中的重寫方法只能聲明拋出該異常(已檢查)或其超類。 否則你將失去多態性,因此在Java中不允許

  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。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM