2013-09-05 44 views
0

我知道的重寫方法的情況Java遵循動態綁定。但是如果我們從引用子對象的父引用變量中調用一個僅子方法,就會出現編譯錯誤。
爲什麼java遵循這種設計(即爲什麼沒有第二種情況下的動態綁定)?爲什麼不同的設計爲動態綁定和從父類調用僅子方法?

class A{ 
    public void sayHi(){ "Hi from A"; } 
} 


class B extends A{ 
    public void sayHi(){ "Hi from B"; 
    public void sayGoodBye(){ "Bye from B"; } 
} 


main(){ 
    A a = new B(); 

    //Works because the sayHi() method is declared in A and overridden in B. In this case 
    //the B version will execute, but it can be called even if the variable is declared to 
    //be type 'A' because sayHi() is part of type A's API and all subTypes will have 
    //that method 
    a.sayHi(); 

    //Compile error because 'a' is declared to be of type 'A' which doesn't have the 
    //sayGoodBye method as part of its API 
    a.sayGoodBye(); 

    // Works as long as the object pointed to by the a variable is an instanceof B. This is 
    // because the cast explicitly tells the compiler it is a 'B' instance 
    ((B)a).sayGoodBye(); 

} 

回答

1

之前方法調用的動態調度可進入行動,代碼要經過編譯器。當您使用類C的引用調用方法時,編譯器會在該類C中查找該方法的聲明。編譯器只關心它的引用類型。它只能驗證對那麼多信息的方法調用。如果它找不到類C中的方法,它會給你編譯器錯誤。

因此,對於調用:

a.sayGoodBye(); 

由於aA類的引用,編譯器會尋找在A類中的方法,如果不能找到,它會給編譯器錯誤。

+0

但在運行時,它遵循動態綁定。 意思是我可以說爲了調用'a.sayHi()'編譯嘗試在A中找到'sayHi()'sayHi()'聲明並且它存在於那裏,所以沒有錯誤。然後在運行時根據對象(即內存地址)調用東西,並且存在C的sayHi()的定義,所以它被調用。 對於方法'sayGoodbye',當你在編譯時得到錯誤(正如你所解釋的),應該沒有問題是在運行時調用哪個定義。 –

+0

@knoxxs。是的。在代碼甚至不編譯時,在運行時沒有行爲問題。 –

0

想這樣:當B擴展A;這意味着

B = <All non-private stuff of A> + Its own stuff 

這意味着B的全部使用A的東西特權(其狀如成爲B的一個子集)

,但一個從來不知道關於B在這裏,什麼B包含;所以,它不能使用B的東西。如果有的話需要迫使A表現得像B(我們使用的是cast),並且從這裏開始A is not B;該投射將在運行時失敗。

要了解更多關於Java鑄件,請閱讀This thread

+0

但是爲什麼在重寫A的情況下可以訪問B的方法定義? –

+0

我沒有得到'重寫A'的東西?你能否添加一個重寫A和訪問B的方法的例子?如果你在說你的例子中的第二種情況失敗,那是因爲在編譯時,引用是類型A;所以只有A的方法可見。如果您知道A確實在B上保留引用,您需要使用Casting來告訴編譯器。由於B是A的孩子,因此B上的任何引用都不需要轉換,因爲編譯器肯定知道B是A(因此它可以像A一樣)。 – gyan

+0

查看當您調用'a.sayHi()'時打印的內容。 –

相關問題