2017-03-10 153 views
0

我正在寫一個程序,我創建一個抽象類鳥。在這個類中有一個叫做chirp()的方法,它打印出「chirp」。我做了兩個額外的課程,叫做Goose和Mallard,它們是從Bird延伸出來的,用重複的chirp方法打印出不同的聲音:「Honk」&「Quack」。如果我要添加另一個名爲Crow的擴展自Bird的類,我將如何編寫一個不會覆蓋的方法chirp?抽象類和抽象方法

我的方法是使方法啁啾與不同的方法簽名。我認爲是這樣做的,但不是因爲我想要它而編譯。

此外,如果我是做鳥類抽象我需要什麼樣的變化做出烏鴉類中的方法...

這裏是我的代碼至今:

import java.util.Scanner; 

public abstract class Bird { 

    public void chirp() { 
     System.out.println("chirp"); 
    } 

    //if chirp made abstract 
    public abstract void chirp(); 

} 

public class Goose extends Bird { 

    public void chirp() { 
     System.out.println("Honk"); 
    } 

} 

public class Mallard extends Bird { 

    public void chirp() { 
     System.out.println("Quack"); 
    } 

} 

public class Crow extends Bird { 

String sound; 

public void chirp(String x) { 
    sound = x; 
} 

} 

public class Problem10 { 

    public static void main(String[] args) { 
     // TODO Auto-generated method stub 
     //Demonstration of polymorphism 
     Bird goose = new Goose(); 
     Bird mallard = new Mallard(); 
     goose.chirp(); 
     mallard.chirp(); 


     //Reference Variable 
     Bird bird = null; 

     //Prompt the user to enter a number that is either 1 or 2 
     Scanner scanner = new Scanner(System.in); 
     System.out.println("Input number either 1 or 2: "); 
     int inputInt = scanner.nextInt(); 
     if (inputInt == 1) { 
      bird = new Goose(); 
     } 
     else if (inputInt == 2) { 
      bird = new Mallard(); 
     } 
     else if (inputInt == 3) { 
      bird = new Crow(); 
      bird.chirp("Crow"); 
     } 
     bird.chirp(); 
    } 

} 
+0

'Crow#chrip(String)'不會覆蓋'Bird#chip()',因爲'Crow#chirp'增加了一個在'Bird#chirp'中不存在的參數。你將不得不刪除參數,或重新考慮你的設計 –

+0

那麼,編譯時會發生什麼?什麼是錯誤信息?你不瞭解它嗎?變鳥的類型是什麼?鑑於這種類型,編譯器如何知道該變量引用的對象中有一個方法chirp(String)? –

+2

@Surace:不,抽象類不需要*有一個抽象方法。在上面的例子中註釋掉抽象方法,你會發現它編譯*很好*。 – Makoto

回答

1

您對抽象三種選擇:

  • Bird是抽象的,但chirp不是:這意味着有作爲一個具體的「鳥」沒有這樣的事。 「鳥」是一個概念,像事物一樣組合在一起。 chirp具體的事實意味着如果所有「鳥類」不決定重寫它,它們將默認說「啁啾」。

  • Bird是抽象的,所以是chirp:同上,除了現在沒有默認的「chirp」;任何「鳥」都必須拿出自己的唧唧喳喳。

  • Bird不是抽象的,也不是chirp:在這種情況下,現在確實存在這樣的事情是真實具體的「鳥」是由像「烏鴉」和「鴨子」多個派生的東西不同。所有真正的「鳥」都會說「唧唧聲」,更多派生的「鳥」會默認說「啁啾聲」,除非他們決定重寫它。

在所有這三種情況下,您可以治療多個派生類型的「鳥」的鳥類,甚至當沒有真正具體的鳥類。

重寫如果您有不同的選擇,以及:

  • 不要忽略:你得到的默認行爲如上所述。如果方法是抽象的,這不是一個選項。

  • 陰影:這意味着更多的派生類型有一個與基類型名稱相同的方法,但它實際上並沒有「覆蓋」它。在這種情況下,如果你把鵝作爲鵝,它會說「鳴笛」,但如果你把鵝作爲鳥,它會說「唧唧」。換句話說,名爲的方法取決於您用來稱之爲的參考。 (我不是100%確定你可以用Java來做到這一點,並且迄今還沒有找到一個例子。)

  • 覆蓋:這意味着你確實覆蓋了該方法。即使你把鵝作爲鳥,它仍然會說「鳴」。這就是所謂的多態性,因爲現在你可以擁有一個「鳥類」列表,即使你將它們當作鳥類,它們也將以自己獨特的重寫方式執行它們的任務。

+0

在Java中不會有「影子」選項。 –

1

我認爲你已經從你編寫的代碼中獲得了99%左右。原因如下:

重載方法 - 具有相同名稱但參數列表不同的方法 - 不會相互衝突。

典型的例子,如果你離開你的抽象類的chirp定義,具體方法好像你只是定義的抽象方法,那麼你只需要添加到您的Crow類來獲得它到chirp正確:

public class Crow extends Bird { 

    String sound; 

    // Use this to actually refer to Crow's chirp sound defined prior 
    public void chirp() { 
     System.out.println(sound); 
    } 

    public void chirp(String x) { 
     sound = x; 
    } 

} 

您可以創建一個重載的方法就好了,但考慮到你是從一個抽象類擴展,你仍然負責處理根據您想要完成的任務調用層級。如果Crow定義了自己的方式來根據其中的字段獲取聲音,那麼您需要負責在該實例上填充該字段Crow

0

如果你想在這是由一個Bird變量引用的Crow實例調用方法,

Bird crow = new Crow(); 

你必須Bird定義和Crow覆蓋的方法。變量類型(Bird)在確定編譯時間變量可以達到的方法。對象類型(Crow)在確定運行時間哪些可能的覆蓋將實際運行。因此,如果您想Bird crow撥打chirp(String),這種方法必須存在於Bird

您可以通過在構建器,設置器或輔助方法中設置Crow中的聲音來解決此問題。

Bird bird = new Crow("croak"); 
bird.chirp(); 

Crow crow = new Crow(); 
crow.setSound("croak"); 
Bird bird = crow; 
bird.chirp(); 

public class Crow { 
    public void chirp() { 
    play(getSound()); 
    } 

    private Sound getSound() { 
    Sound sound = // Figure out what sound 
    return sound; 
    } 
} 

選擇取決於聲音的判定如何動態必須。

0

我認爲這裏的解決方案不是關於繼承,而是命名。

並非每個Bird都可以chirp。例如,一個Crow可能kaw和一個Duck可能quack

這應該告訴你,一Bird不能被允許chirp如果你也希望有一個Duckquack,或Crowkaw

相反,您應該將chirp視爲Noise的一種類型。所有產生噪音的鳥類都會產生噪音(否則它們不會成爲製造噪音的鳥類)。

所以編纂這一點,你可能一旦你有你的聲音有一些像

public interface Noise { 
    void makeNoise(); 
} 

public class Chirp extends Noise { 

    public void makeNoise() { 
     System.out.println('Chirp!'); 
    } 
} 

public class Quack extends Noise { 

    public void makeNoise() { 
     System.out.println('Quack!'); 
    } 
} 

,你有一對夫婦爲鳥類選項。你只能有一個Bird類,以及什麼類型的需要噪聲決定了它是什麼類型的鳥,像

public class Bird { 
    private final Noise noise; 

    public Bird(Noise noise) { 
     // ... 
    } 

    public final void makeNoise() { 
     noise.makeNoise(); 
    } 
} 

隨着客戶端代碼類似

Bird duck = new Bird(new Quack()); 
Bird robin = new Bird(new Chirp()); 

其他選項擴展這個通過聲明知道他們將使用什麼類型的噪聲的類來進行一點點修改。

public class Duck extends Bird { 

    public class Duck() { 
     super(new Quack()); 
    } 
} 

這是使用像

Bird duck = new Duck(); 

我要說更喜歡第一種選擇,除非你有這才能真正真的只適用於Duck概念,並簡單地將其他Bird小號沒有這個概念。