[英]Abstract Class and Abstract Method
我正在编写一个程序,在其中创建抽象类Bird。 在此类中,有一个称为chirp()的方法,该方法可打印出“ chirp”。 我制作了另外两个名为Goose和Mallard的类,它们从Bird扩展而来,并具有覆盖的rp声方法,可打印出不同的声音:“ Honk”和“ Quack”。 如果我要添加另一个从Bird扩展的名为Crow的类,我将如何编写一个不重载的方法chirp?
我的方法是使具有不同方法签名的方法线性调频。 我认为是这样做的,但没有按照我的要求进行编译。
此外,如果我要在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();
}
}
对于抽象性,您有三个选择:
Bird
是抽象的,但chirp
不是:这意味着不存在具体的“鸟”之类的东西。 “鸟”是将事物归类在一起的一般概念。 chirp
是具体的事实意味着,如果所有“鸟”都决定不覆盖它,则默认会说“线性调频”。
Bird
是抽象的, chirp
也是如此:与上面相同,除了现在没有默认的“ chirp”。 任何“鸟”都必须提出自己的of声。
Bird
是不是抽象的,也不是chirp
:在这种情况下,现在确实存在这样的事情是真实具体的“鸟”是由像“乌鸦”和“鸭子”多个派生的东西不同。 所有真正的“鸟”都说“ chi”,而更多派生的“鸟”将默认说“ chi”,除非他们决定覆盖它。
在这三种情况下,即使没有真正的具体鸟,也可以将更多派生的“鸟”视为鸟。
覆盖时,您还有多种选择:
不要覆盖:您将获得上述默认行为。 如果方法是抽象的,则这不是一个选择。
阴影:这意味着派生性更高的类型具有与基本类型同名的方法,但实际上并未“覆盖”它。 在这种情况下,如果您将鹅视为鹅,则会说“鸣喇叭”,但是如果您将鹅视为鸟,则会说“ chi”。 换句话说,被调用的方法取决于您用来调用它的引用 。 (我不确定100%是否可以用Java做到这一点,并且到目前为止还没有找到示例。)
覆盖:这意味着您确实覆盖了该方法。 即使您将鹅当做鸟,它也会说“鸣喇叭”。 这被称为多态,因为现在您可以拥有“鸟”的列表,即使您将它们视为鸟,它们也都将以自己独特的覆盖方式执行任务。
我认为您所编写的代码中大约有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
实例上填充该字段。
如果您要在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;
}
}
选择取决于确定声音的动态程度。
我认为这里的解决方案不是关于继承,而是命名。
并非每Bird
都能chirp
。 例如, Crow
可能会kaw
而Duck
可能会quack
。
这应该告诉你, Bird
不能被允许chirp
,如果你也希望有一个Duck
给quack
,或Crow
到kaw
。
相反,您应该将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
根本没有该概念。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.