2010-10-27 37 views
1
class B { 
    void process()throws Exception{ 
     System.out.println("hi sh"); 
    } 

} 
class C extends B { 
    void process(){ 
     System.out.println("hhhhhh"); 
    } 

    public static void main(String args[]){ 
     B a=new C(); 
     try{ 
      a.process(); 
     } 
     catch(Exception e) 
     { 
     } 
    } 
} 

在調用process方法時,我們必須使用try catch塊。但是,如果我只將C的對象存儲在C的引用變量中,即C a=new C(),則不需要嘗試catch塊。在繼承中使用異常

誰能告訴我爲什麼?

+1

格式不錯,你知道.. – Roman 2010-10-27 13:41:03

+0

可能是[Java的重複。在overriden方法中移除throws聲明,但編譯器在調用時需要try/catch blok。](http://stackoverflow.com/questions/9413599/java-removing-throws-declaration-in-overriden-method-yet-compiler- want-a-try-c) – Raedwald 2014-09-16 07:02:57

回答

5

編譯器不能(通常)告訴運行期間變量a將具有哪種類型。因此,它(始終)採取安全路線,並要求您在呼叫周圍放置try/catch

當你

C a = new C(); 

相反,編譯器可以確保B.process()不是在運行時調用,這樣你可以調用它,而不try/catch

1

分配引用將在運行時完成。

異常聲明檢查在編譯時完成。

如果你寫

B a=new C();// 

這裏編譯器知道也可稱爲的該方法運行它時的決定,以便它迫使我們處理異常。

但是如果你使用

C a=new C() ; 

編譯器是相當已將C的方法將被調用,所以它不聲明拋出異常,所以其允許

0

由於B.process()簽名void process() throws Exception

在您的C班級中,您已將簽名縮小到void process()

當您聲明類型爲B的引用時,您需要處理B.process()被聲明爲引發的(檢查)異常。

當您聲明引用是C類型時,不會有例外C.process()被聲明爲拋出。

當你實例化一個對象作爲B a = new C(),然後a運行C的,但聲明的類型是B。編譯器將a視爲B類型,因爲您將其聲明爲B。這是工作中的多態性。

0

這隻發生在檢查異常,這是由於多態性。

在您機箱C is-a B上,當你調用process()可能拋出checked異常(你處理的)。

處理異常的最安全,迫使開發者處理這個異常每當process()被稱爲上一個 B(這也可能是C,但你不知道,在運行之前)。

0

此處而調用過程方法 我們必須使用try catch塊但 如果我C的對象存儲在只即,C A =新的C(C的 參考變量),那麼嘗試catch塊不是 needed.Can任何人可以告訴我爲什麼 原因?

你需要記住的是,run-time類型的引用不一定是相同declared類型。例如:

Number n = new Integer(1); 

這聲明電量爲聲明類型java.lang.Number參考的特定的類/類型java.lang.Integerjava.lang.Number一個子類的一個參考。

有關實際的信息運行時間類型(通常)僅在運行時可用。但編譯器只能在編譯時運行。在編譯時,編譯器(通常)只知道聲明的類型。

由於它通常只知道宣稱的類型,因此它只能用於決定什麼可以編譯,哪些不能。也就是說,javac只能在編譯時根據它所知道的(或者可以推斷出來的)來執行規則。

再回到你的代碼示例:

編譯器看聲明類型的引用(在此情況下,參考aB類型)。基於此,編譯器知道方法B.process()會引發需要強制執行的檢查異常。

也就是說,無論是

B a=new C(); 

B a=new B(); 

聲明的是B類型,其process()方法拋出檢查異常的a。但是,如果您具備以下條件:

C a = new C(); 

屆時,宣佈型爲C,不B。由於子類削弱了其繼承方法的先決條件,因此C可以自由削弱process()的前提條件。也就是說,它可以聲明C.process()拋出由B.process拋出的異常集合的子集(在C.process()的情況下,它是空集。)

這是有點關係的Liskov substitution principleDesign by Contract,與載明下列原則前者(感謝維基百科)(3,4直接關係到你在Java代碼中觀察到的):

的亞型方法的參數
  1. 逆變。
  2. 子類型中返回類型的協方差。
  3. 除了 以外,子類型的方法不應引發新的異常,其中這些異常本身是 超類型的 方法拋出的異常的子類型。
  4. 先決條件不能在子類型中加強。
  5. 後代不能在子類型中被削弱。
  6. 超類型的不變式必須保存在子類型中。

Java編譯器僅僅是試圖執行一些原則,並通過實際的目的,它採用了宣佈類型的引用變量來確定如何予以執行。

0

當我們寫:

B a=new C(); 

我們都隱含類型轉換的C對象在運行時會調用C的過程中()對象B.

a.process(); 

但在編譯時,對編譯器a仍然是B的對象,因爲B有process()拋出異常,所以它必須使用try/catch捕獲。

如果我們使用:

C a = new C(); 
a.process(); 

在編譯時,編譯器一個仍然是C的對象(可以含有參考其他子類對象),併爲C的有過程()不拋出任何異常等等無需抓住使用try/catch。

+1

這幾乎是@aioobe在2年前回答的... – MByD 2012-09-22 01:39:53