[英]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中不允許
我們不能在重寫方法中引入新的已檢查異常,但可以具有子檢查異常或與父類中處理的異常相同的異常。 即使我們這樣做,如果我們使用父引用引用子對象,那么編譯器將強制捕獲在父類方法中聲明的異常,然后查看下面的示例:
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.