2017-03-02 105 views
0

考慮以下基本/派生類:從Java子類中調用的方法不是在父類

public class Car { 
    private int cylinders; 

    public Car(int cyl) { 
     cylinders = cyl; 
    } 

    public int getCylinders() { 
     return cylinders; 
    } 
} 

public class SportsCar extends Car { 
    private int topSpeed; 

    public SportsCar(int cyl, int top) { 
     super(cyl); 
     topSpeed = top; 
    } 

    public int getTopSpeed() { 
     return topSpeed; 
    } 
} 

現在,請考慮以下兩個對象:

SportsCar lambo = new SportsCar(8,255); 
    Car m5 = new SportsCar(10,240); 

的以下方法調用編譯正常:

lambo.getTopSpeed(); 

然而,隨着錯誤調用此方法突破「無法找到符號 - 方法getTopSpeed()」

m5.getTopSpeed(); 

現在我明白getTopSpeed方法必須在基類中存在以便它因爲m5編譯是一個Car類型,所以如果我包含getTopSpeedCar那麼m5.getTopSpeed();很好地編譯。

我的問題是:

  1. 爲什麼錯誤「無法找到符號 - 方法getTopSpeed()」在編譯時發生,而不是運行時間?
  2. 爲什麼「後期綁定」不能防止這個錯誤?
  3. 假設getTopSpeedCar實現(因此它編譯)在程序運行時,不編譯器首先檢查以查看是否存在getTopSpeedCar,然後檢查,看它是否超過深重在SportsCar還是隻是「知道「它已經從編譯器中被覆蓋了,並直接使用了過度使用的方法?
+1

你的第一個問題,在此的其他問題的回答(http://stackoverflow.com/a/11466790/1079354)可以合理地第一句回答。其他的部分,我會鼓勵對JLS的一些細讀。 – Makoto

+1

'm5'是'Car'類型的引用變量,這意味着您只能調用'Car'中定義的方法。如果您想使用'SportsCar'中的方法,則必須將'm5'明確地轉換爲'SportsCar'。 – Logan

+0

編譯器無法通過父類型的變量「查看」派生類型的成員。涉及到兩種類型,編譯器使用的_variable_的聲明類型以及JVM使用的_object_的運行時類型。您期待編譯器處理_variable_,就好像它可以看到_object_的運行時類型。它不能。 –

回答

1
  1. 的Java是靜態類型語言,所以變量類型應該在編譯時是已知的。如果編譯器已知的類型不公開這種方法 - 這是編譯失敗。確切的說是不讓它運行的原因。

  2. 爲什麼要這樣呢?它只是發現方法體遲了,而不是簽名。靜態類型意味着簽名必須在編譯時滿足。

  3. 運行時JVM試圖找到最具體的實現。在SportsCar中,就你的情況而言。如果它是從父項繼承的,但是在子項中不存在,則使用父代碼。

如果您需要從具體的子這是變量類型未接電話的方法 - 可以在運行時在自己獲得ClassCastException異常的風險投它。

+0

或者,如果您需要子類型,則只需將變量聲明爲子類型即可。鑄造是代碼氣味。 –

+0

嗯,這取決於。是的,這增加了運行時異常的風險。但是,另一方面,如果你知道你在做什麼 - 這可以。例如,對於消息類型,Akka/Java風格的模式匹配如何? – iTollu

+0

它仍然是代碼味道。在絕大多數情況下,我已經看到'instanceof'的使用,這是爲了解決類型分析中的一個空白。 –

1

這是因爲當編譯器看到這一點:

SportsCar lambo = new SportsCar(8,255); 
Car m5 = new SportsCar(10,240); 

它知道蘭博是跑車,但只知道M5是一輛汽車。如果你想獲得M5的最高速度,你必須把它轉換爲跑車第一:

((SportsCar)m5).getTopSpeed(); 

大多數我見過鑄造,然而,該變量轉換爲另一個變量第一時間:

SportsCar sportsM5 = (SportsCar)m5; 
sportsM5.getTopSpeed(); 

This aspect of polymorphism in Java confused me once when I was passing an object to a method.