2012-01-18 45 views
2

在以下代碼:矛盾例外規格相同的方法在不同的接口

class MyException extends Exception{} 

interface Bread 
{ 
    public void eat() throws MyException; 
} 

interface Fringe 
{ 
    public void eat() throws RuntimeException; 
} 

public class Test implements Fringe , Bread // #5 
{ 
    public static void main(String[] args) 
    { 
     Fringe best = new Test(); // #1 
     best.eat();// #2 
    } 

    public void eat() throws RuntimeException // #3 
    { 
     System.out.println("Test"); 
     throw new RuntimeException(); // #4 
    } 
} 

MyException不是RuntimeException。爲什麼我們可以宣佈Test.eat()投擲RuntimeException,但不是一般的Exception

+0

確定您要檢舉的內容? MyException實際上並沒有在這裏的任何地方拋出。 – cha0site 2012-01-18 12:08:09

回答

4

這是因爲在重寫方法中,您只能拋出異常低於或等於合同中定義的異常。因此,eat()可以拋出MyException及其子類,但不是MyException以上的任何東西,這就是Exception。運行時異常不是這個規則的一部分,你可以隨意拋出它們,因爲它們沒有被「檢查」。

這是因爲我們假設我使用Bread接口來訪問Test類的實例。如果我撥打eat()方法,我可以「檢查」MyException,因爲它是合同的一部分,但如果底層實施決定拋出「更高」異常,它將不會被我的MyException catch塊捕獲,因此違反了合同。看看下面的代碼爲例:

Bread b = new Test(); 
try { 
    // if this throws Exception, it won't be caught in the catch block 
    // thereby violating contract 
    b.eat(); 
} catch (MyException e) { 
    e.printStacktrace(); 
} 
2

兩點:

  • 你不能聲明它拋出Exception,因爲它會再扔多了一個普遍的例外是什麼eat()方法Bread接口指定。從超類或接口繼承的方法不能拋出比超類或接口中指定的更多的一般異常。
  • 您可以聲明它拋出RuntimeException,因爲無論您是否在throws子句中指定它們,方法總是可以拋出未經檢查的異常。 (因此指定它可以拋出RuntimeException是多餘的)。

要解釋我在第一點中提到的規則的原因:假如你這樣做:

// Allowed because Test implements Bread 
Bread obj = new Test(); 

如果你現在打電話obj.eat(),編譯器需要檢查,如果你正確地處理所有檢查的異常那可能發生在那個電話中。它通過查看變量obj的類型(Bread)來完成此操作。 Bread接口指定eat()可以拋出MyException(並且隱含地,MyException的子類)。

如果您Test.eat()方法被允許拋出一個更普遍的一種檢查異常,如Exception,那麼編譯器不能只看中你處理所有正確checked異常obj類型檢查。

爲了防止出現這個問題,規則是重寫的方法不允許拋出更多的一般異常。

0

一個最重要的方法只能扔那些滿足IS-A與覆蓋方法引發的異常關係的異常。

如果你嘗試在你的類丟Exception而接口拋出MyException ...編譯器看到,如果下面的語句是正確的:

例外是-A MyException - 這是假的,你知道的。所以編譯器會拒絕它。

因此,您只能從子類中的方法中拋出一個更具體的異常。

要爲大家介紹的運行時異常問題:

對於拋出運行時異常,也就相當於,如果你還沒有明確寫它。所以編譯器會忽略它。因爲即使你沒有提到它,一個方法可以在運行時拋出異常。