2017-03-10 52 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小号没有这个概念。