2014-09-22 71 views
0

當繼承和類型轉換混合時,我有點困惑。我想了解java編譯器在繼承中選擇正確的方法和變量時遵循的規則。java編譯器如何在繼承中選擇正確的方法和變量

我看過類似

變量在編譯時綁定和方法在運行時綁定。

第二個是從stackoverflow(@約翰碟)

重載分辨率(其方法簽名稱)在編譯時被確定,基於所述編譯時間類型兩者的方法目標和參數表達式

該方法簽名的實現(覆蓋)基於目標對象在執行時的實際類型。

但問題是,它們是對特定情況的解釋,並且不考慮其他因素(如異常處理)時要遵循的一般過程。

這可能是不好的做法,但假定重寫方法和變量(隱藏在static變量的情況下)。

現在,如果java編譯器必須在編譯時選擇需要調用哪個方法/變量,那麼它將遵循什麼算法?同樣在運行時,java編譯器將使用哪種算法(基於引用被使用的對象的實際類型)?

+0

異常處理不是重載解析的一部分(儘管它們可能意味着所選的重載無效),並且變量不會被覆蓋 - 它們是隱藏的。如果你正在尋找詳細的規則,我建議你閱讀JLS,例如http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12 – 2014-09-22 16:48:47

+0

編譯器不會選擇,並且在編譯時不調用*方法。 JVM有責任在運行時使用虛擬方法表來執行此操作。 – 2014-09-22 16:50:26

+0

「假定重寫了方法和變量」沒有「重寫變量」這樣的事情。 @JonSkeet稱之爲「重載決議」意味着選擇_signature_方法。簽名是方法名稱的擴展形式。聲明爲foo(int i)的方法與聲明爲foo(String s)的方法具有不同的簽名(名稱)。編譯器可以在編譯時總是告訴方法調用表達式的方法簽名。當父類和子類都聲明具有相同_signature_的方法時,會發生_Overriding_。這就是在運行時解決的問題。 – 2014-09-22 16:53:44

回答

5

所有方法簽名和變量都在編譯期間被驗證,但實際的方法調用是在運行時完成/解析的。

例如:

class A { 
int i=5; 
public void doSomething(){ 
//print "in A" 
} 
} 

class B extends A{ 
int i=10;  
public void doSomething(){ 
// print "in B" 
} 

public static void main(String[] args){ 
A a = new B(); 
a.doSomething(); 
} 
} 

現在,當你調用a.doSomething();,在編譯過程中,編譯器只檢查doSomething()是否爲A級(左基準)來定義。它甚至不關心該方法是否也被定義爲B類。即使該方法在B中不存在,該程序也可以很好地編譯。

接下來,在運行時,JVM根據對象的類型(B)動態地決定調用哪個方法。

因此,打印"in B"

現在,回到田野。訪問字段在編譯期間解決。所以,如果一個字段在編譯期間不存在,那麼編譯失敗。這些字段是基於引用類型調用的。因此,a.i將打印5A's的值爲i),因爲該字段在編譯期間已解決。因此,不同之處在於,方法調用在運行時期間被解析,它們的簽名在編譯期間需要/被檢查,因爲在編譯期間字段被檢查/解析。

+0

您應該澄清方法調用和字段訪問之間運行時行爲的差異。 – 2014-09-22 16:57:26

+0

@SotiriosDelimanolis - 完成 – TheLostMind 2014-09-22 17:07:41