2017-03-10 16 views
0

抽象クラスBirdを作成するプログラムを作成しています。このクラスには "チャープ"を出力するchirp()というメソッドがあります。 Birdから拡張されたGooseとMallardという2つの追加クラスを作成しました。これは異なる音を出力するチャープメソッドをオーバーライドしています: "Honk" & "Quack"。私がBirdから継承するCrowと呼ばれる別のクラスを追加する場合、どのようにオーバーライドしないメソッドチャープを書くのでしょうか?抽象クラスと抽象メソッド

私のアプローチは、異なるメソッドシグネチャでメソッドチャープを作成することです。私はこれをしたと思うが、私がそれを望むように編集していない。私はここで

がコードです...鳥私はカラスクラスに作成する必要がありますどのような変更抽象のメソッドを作成した場合

また、私がこれまで持っている:

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)'は、 'Crow#chirp'が' Bird#chirp'に存在しないパラメータを追加したため、 'Bird#chip()'をオーバーライドしません。パラメータを削除するか、デザインを再考する必要があります –

+0

コンパイルするとどうなりますか?エラーメッセージとは何ですか?あなたはそれについて何を理解していませんか?可変鳥のタイプはどれですか?その型を考えると、コンパイラはその変数によって参照されるオブジェクトにメソッドchirp(String)があることをどのように知ることができますか? –

+2

@Surace:いいえ、抽象クラスに抽象メソッドを持たせる必要はありません。上記の例の抽象メソッドをコメントアウトすると、* fine *がコンパイルされることがわかります。 – Makoto

答えて

1

あなたは抽象性のための3つの選択肢があります。

  • Birdは抽象的ですが、chirpではありません。これは、具体的な「鳥​​」のようなものがありませんを意味します。 「バード」は物事をまとめた一般的な概念です。 chirpが具体的であるという事実は、すべての「鳥」が、それを無効にすることを決定しなければ、デフォルトで「チャープ」と言うことを意味する。

  • Birdは抽象的なですので、chirpです:上記以外は既定の "チャープ"はありません。 「鳥」であるものは、それ自身のチャーピングの方法を考え出す必要があります。

  • Bird抽象的でもないchirpではありません。この場合には、今「カラス」と「アヒル」のようなより多くの派生のものとは区別される真の具体的な「鳥​​」のようなものが存在します。すべての真の「鳥」は「チャープ」と言い、より派生した種類の「鳥」は、それを上書きすることを決めない限り、デフォルトで「チャープ」と発音します。これらの例すべての3つで

、あなたは真の具体的な鳥が存在しない場合でも、鳥のように「鳥」のより派生の種類を扱うことができます。あなたにも、さまざまな選択肢がありますオーバーライドするとき

  • は上書きしないでください:上記で説明したように、あなたはデフォルトの動作を取得します。メソッドが抽象メソッドである場合、これはオプションではありません。

  • 影:これは、より多くの派生型が基本型と同じ名前のメソッドを持つことを意味しますが、実際にはそれを「上書き」しません。この場合、ガチョウをガチョウとして扱うと「ホーク」と言われますが、ガチョウを鳥類として扱うと「チャープ」と表示されます。言い換えれば、と呼ばれるメソッドは、それをと呼んだときの参照によって異なります。 (私はあなたがJavaでこれを行うことができると100%確信しておらず、これまでの例を見つけることができませんでした。)オーバーライド:これは実際にメソッドをオーバーライドしたことを意味します。あなたが鳥として鳥を扱っても、それはまだ "ホーク"と言います。これは多形性と呼ばれています。なぜなら、あなたは「鳥」のリストを持つことができるからです。鳥類として扱っているにもかかわらず、彼らはすべて独自のオーバーライドされた方法でタスクを実行します。

+0

Javaでは "shadow"オプションはありません。 –

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変数、

Bird crow = new Crow(); 

によって参照されますCrowインスタンスのメソッドを呼び出したい場合。変数タイプ(Bird)は、コンパイル時にの変数に到達できるかどうかを決定します。オブジェクトタイプ(Crow)は、実行時間で実際に実行されるオーバーライドを決定します。したがってBird crowchirp(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

ここでの解決策は、継承についてではなく、むしろ名前を付けることだと思います。

いずれもBirdchirpではありません。たとえば、CrowkawDuckquackとなる可能性があります。

これはあなたにもDuckkawCrowquackに、またはしたい場合はBirdchirpに許されてはならないことを教えなければなりません。

代わりにをタイプとして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!'); 
    } 
} 

のようなものがあるかもしれません。他のオプションは、このAを拡張してあなただけのBirdクラスを持つことができ、そしてそれが取るノイズの種類は

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

のようなクライアントコードの何かを

public class Bird { 
    private final Noise noise; 

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

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

のように、それは鳥の種類を判別します彼らが使用するノイズの種類を知っているクラスを宣言することによって、少しだけ。あなたが本当にが本当に単にDuckに適用され、他のBirdのことができる概念を持っていない限り、私は、最初のオプションを好むと言うでしょう

Bird duck = new Duck(); 

のように使用されて

public class Duck extends Bird { 

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

そのコンセプトはありません。

関連する問題