2016-02-19 24 views
-2

在下面的代碼中,我在b.printname();處得到一個編譯器錯誤。據我瞭解,錯誤在於編譯器以非多態方式有效地運行(即編譯器本質上只選擇查看操作數的左側,因此b是一個問題)。由於b的類型是Question,並且由於Question沒有no-args printName方法,所以會出現編譯錯誤。那是對的嗎? 現在假設這是正確的,我的問題是爲什麼?編譯器當然應該知道問題b是指實際上支持no-args printName方法的對象?例如。如果你看看編譯器在轉換方面的表現如何,那麼編譯器會因爲缺少一個更好的詞而多態行爲,或者以不同的方式使編譯器知道發生了什麼,操作數並根據該知識進行操作。一個例子是,如果接口類型是指實現接口的對象,則編譯器會查看語句的右側(即實現接口的對象)並決定不需要轉換。那麼爲什麼編譯器不這樣做呢,爲什麼它看起來並沒有看到所討論的對象實際上是一個藍色,而藍色確實支持no-arg方法printName?Java編譯時非多態性

public class Polymorf3 { 



    public static void main(String[] args){ 
     Polymorf3 me = new Polymorf3(); 
     me.doStuff(); 
    } 

    public void doStuff() { 
     Bat a = new Bat(); 
     Question b = new Blue(); 
     //a.printName(); 
     a.printName(a.name); 
     b.printName(); // Compiler Error:Required String Found no args 
    } 
    abstract class Question { 
     String name="Question_name"; 
      public void printName(String name){ System.out.println(name);} 
    } 
    class Bat extends Question { 
     String name = "Bat_Bruce"; 
     //public void printName(){ System.out.println(name);} 

    } 
    class Blue extends Question { 
     String name = "Clark"; 
     public void printName() {System.out.println(name);} 
    } 
} 
+1

因爲這裏'b'包含'Question'類的引用。 – Satya

回答

1

雖然bBlue類型的,因爲你宣佈它爲Question b = new Blue();,編譯器將其視爲Question類型,因此這只是提供給它的接口沒有一個明確的轉換:

((Blue)b).printName(); 

或者,您可以聲明它爲Blue b = new Blue();b.printName();不會引發編譯時錯誤。

本質上這裏發生了什麼是你聲明你的新變量b在更高的抽象水平,因此可供b唯一printName方法是一個抽象的較高水平,一個與ARGS。

編輯:

OP問爲什麼,編譯器將b作爲Question即使它作爲Blue初始化。考慮以下幾點:

Question q = new Blue(); 
// ... some other code... 
q = new Bat(); // Valid!! 
q.printName("some string"); 

現在考慮明天,其他一些開發商進來,並將其更改爲以下:

Blue q = new Blue(); 
// ... some other code... 
q = new Bat(); // Invalid!! Compiler error 
q.printName("some string"); 

在需要抽象的最高級別聲明一個變量爲您的操作意味着你稍後可以更輕鬆地更改實現,而不會影響所有其他代碼。因此,應該清楚爲什麼Java編譯器將b視爲Question。這是因爲b可以在任何時間,成爲BlueBat一個實例,因此將其視爲實現(BlueBat)將允許一些其他非ARG getName方法違反Question接口的合同。

+0

對不起,我不認爲我的問題很清楚。我理解這個邏輯。我明白,當你將b聲明爲一個Question時,它就像一個Question一樣對待,在這種情況下,Question不支持請求的方法。但是,我的問題涉及Java編譯器。爲什麼編譯器不能處理它所擁有的信息?即當然知道b實際上是藍色,並且它知道藍色支持所請求的方法。 – Risteard

+0

我試圖解決您的後續編輯問題 – Tgsmith61591

+0

謝謝您的肯定回答我的問題。如果可以的話,我會投票給你,但是在提出這個問題之後,我的聲譽已經被破壞了。 :( – Risteard

0

您似乎誤解了多態性意味着什麼。這意味着您可以將派生類的實例視爲它是基類的實例。這包括不調用基類不提供的方法。變量類型通知你可以調用什麼方法,實例化類型決定了這些方法的運行實現。

通過將您的Blue實例置於Question變量中,您需要將其作爲Question對待。如果您想要調用Question類中未提供的Question變量的方法,那麼爲什麼它是一個Question變量呢?如果您可以在基類變量上調用派生類方法,它不會是基類變量。

+0

感謝您的迴應,但您可以調用基類變量的派生類方法。例如如果Question實現了請求的(無參數)方法,那麼它將被允許。此外,在運行時,Blue類的實現會啓動。所以我的問題是編譯器將b視爲藍色,因爲它是藍色並且編譯器知道它是藍色,這會是什麼壞處。 – Risteard

+0

多態性的要點是擁有「Question」類型的變量是一種將實例視爲「Question」而不需要了解具體實現的方式。如果你不想像'Question'一樣對待你的對象,那麼你不想使用多態,所以不要將你的變量聲明爲'Question'類型。 – khelwood

+0

謝謝,我想我現在明白了。所以如果說一個動物有方法睡覺和吃,它是孩子狗有方法樹皮。那麼如果狗被當作動物對待,那它就不應該被允許吠叫?很抱歉,這個冗長的問題。 – Risteard