这个问题来自AP计算机科学实践测试。
public class Bird
{
public void act()
{
System.out.print("fly");
makeNoise();
}
public void makeNoise()
{
System.out.print("chirp");
}
}
public class Dove extends Bird
{
public void act()
{
super.act();
System.out.print("waddle");
}
public void makeNoise()
{
super.makeNoise();
System.out.print("coo");
}
}
假设以下声明出现在Bird或Dove以外的类中:
Bird pigeon = new Dove();
通过电话pigeon.act()
打印的内容是什么?
我认为答案是"飞唧唧",但是教科书说答案是"飞唧唧唧唧"。我认为那羽鸽子'只能访问Bird中可用的方法?我的印象是,如果用户想要访问Dove中的方法,那么鸽子就可以了。必须投向鸽子。
Bird pigeon = new Bird();
会给出相同的输出吗? Dove pigeon = new Dove();
怎么样?
答案 0 :(得分:4)
简而言之,当您访问act
的{{1}}方法时,会调用pigeon
的覆盖。
我认为那羽鸽子'只能访问Bird中可用的方法吗?
至少,对于没有应用强制转换的情况,这是肯定的。但是,方法Dove
可用于act
类,即静态已知的Bird
类型,因此调用编译正常。
但是,访问方法只能调用它们。调用它们时的哪些方法是在运行时根据pigeon
的动态类型决定的。这是方法覆盖发挥作用的地方,因为pigeon
会覆盖Dove
的方法,但此外它还会调用Bird
的方法。这就是代码击中所有四个打印输出的原因。
Bird
会给出相同的输出吗?
不,输出会有所不同,因为在这种情况下,Bird pigeon = new Bird();
的动态和静态类型都是相同的,即pigeon
,所以只有Bird
' s将调用实现。
答案 1 :(得分:2)
您在这里遇到的是多态。而不是直接回答你的各种问题;我将简单解释你正在观察的案例。
你在Dove的一个实例上调用act()
;这导致超级电话;印刷"飞"。
那个超级方法然后调用makeNoise()
... on"本身"。但正如所说:"本身"是一个鸽子对象;因此你得到了鸽子的声音! " COO"!
然后Dove实施结束;并打印" waddle"。
本质是:调用的方法的确切版本在运行时确定,仅 >取决于调用方法的对象的确切类型。
以上为您提供了所有您自己回答其他问题所需的信息。在这个意义上:不要求答案;请求解释;并使用这些来解决这个难题!
答案 2 :(得分:2)
Dove
执行覆盖类act
的方法makeNoise
和Bird
。覆盖意味着将方法可见的行为更改为子类(在您的情况下为Dove
)。如果子类具有public
或protected
访问修饰符,或者如果它们具有package private
访问修饰符且子类属于与超级相同的包,则子类可见方法 - 类。 pigeon
是Dove
。pigeon.act()
会调用Dove.act
。Dove.act
调用super.act
Bird.act
。Bird.act
打印fly
并致电makeNoise
pigeon
,致电Dove.makeNoise
。Dove.makeNoise
调用super.makeNoise
Bird.makeNoise
。Bird.makeNoise
打印chirp
。Dove.makeNoise
在致电coo
super.makeNoice
答案 3 :(得分:1)
从你的问题“我认为'鸽子'只能访问Bird中可用的方法?我的印象是,如果用户想要访问Dove中的方法,'鸽子'就必须投向Dove。”这实际上是 true 。
让我们尝试在理解中找到mssing链接。
当我们的代码Bird pigeon = new Dove();
Dove
扩展Bird
时,我们的实际对象为Dove
,引用类型为Bird
。由于对象属于Dove
所以它具有方法,来自超类的继承以及添加的方法。
另一个要点是,所有 overriden
方法只有一个实例。它的Overriden意味着同一方法的行为已被修改,它不是一个额外的单独方法。只有一个继承方法的副本,而不是两个。它的重载方法是分开的,只是名称相同但签名不同。这是您在调用任何override方法时获得Dove行为的原因。
这个是简单的super
,使用它,子类可以访问其超类的可访问(可见)实体(实例属性和方法)。如果子类使用super
关键字来调用方法,那么它将调用父类的方法。但同样可以认为子类的作者故意这样做了。一旦编写了类并且创建了这样的类的对象,那么使用.
(点运算符)在对象上,用户只能调用对象中的那些。如果任何方法使用super
关键字作为对象行为的一部分。如果子类对象的子类在子类中被重写,则它不能调用父类方法的行为。
最后是的,如果您希望使用Dove
(超类)的引用调用Bird
(Sub class)的任何其他方法,则需要将其强制转换为{{1} }。