我正在编写一个程序来创建一个抽象类Bird。在这个类中有一个名为chirp()的方法,它打印出" chirp"。我做了另外两个名为Goose和Mallard的课程,这些课程从Bird延伸出来,采用重写的啁啾方法打印出不同的声音:" Honk" &安培; "嘎嘎&#34 ;.如果我要添加另一个名为Crow的类,从Bird延伸,我怎么写一个不会覆盖的方法啁啾?
我的方法是使用不同的方法签名制作方法啁啾。我认为这样做但是没有按照我的意愿进行编译。
另外,如果我在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 :(得分:1)
抽象性有三种选择:
Bird
是抽象的,但chirp
不是:这意味着没有具体的" Bird"。 "鸟"是一个将事物分组在一起的一般概念。 chirp
具体的事实意味着所有的鸟类和#34;将默认说" chirp"如果他们不决定覆盖它。
Bird
是抽象的,chirp
也是如此:与上面相同,除了现在没有默认" chirp&#34 ;;什么是" Bird"必须想出自己的唧唧喳喳的方式。
Bird
不是抽象的,也不是chirp
:在这种情况下,现在确实存在诸如真正的混凝土和#34; Birds"之类的东西。与更多衍生事物不同,例如" Crows" " Ducks"。所有真实的鸟类#34;说" chirp"还有更多衍生出来的鸟类#34;将默认说" chirp"除非他们决定覆盖它。
在所有这三种情况中,您都可以处理更多衍生类型的" Birds"作为鸟类,即使没有真正的具体鸟类。
当覆盖时你也有各种选择:
不要覆盖:您将获得默认行为,如上所述。如果方法是抽象的,那么这不是一个选项。
影子:这意味着派生的派生类型的方法与基本类型同名,但实际上并没有覆盖"它。在这种情况下,如果你将鹅视为鹅,它会说"鸣喇叭",但如果你把鹅视为鸟,它会说" chirp"。换句话说,被称为的方法取决于您用来调用它的引用。 (我不是100%肯定你可以用Java做到这一点,到目前为止还没有找到一个例子。)
覆盖:这意味着您确实覆盖了该方法。即使你将鹅视为鸟,它仍然会说"鸣喇叭"。这称为多态,因为现在你可以拥有一个" Birds"的列表,即使你将它们视为鸟类,它们也将以自己独特的覆盖方式执行任务。
答案 1 :(得分: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
的该实例上填充该字段。
答案 2 :(得分:0)
如果要调用由Crow
变量引用的Bird
实例中的方法,
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;
}
}
选择取决于确定声音的动态程度。
答案 3 :(得分:0)
我认为这里的解决方案不是继承,而是命名。
不是每个Bird
都可以chirp
。例如,Crow
可能kaw
和Duck
可能quack
。
这应该告诉您,如果您还需要Bird
到chirp
或Duck
到{quack
,则Crow
不允许kaw
{1}}。
相反,您应该将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
根本没有有这个概念。