2017-04-26 88 views
4

这个问题来自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 pigeon = new Dove(); 

什么是印刷作为呼叫pigeon.act()的结果?

我认为答案是“飞唧唧”,但教科书说答案是“飞啾咕coo蹒跚”。我认为'鸽子'只能访问Bird中可用的方法?我的印象是,如果用户想要访问鸽子的方法,鸽子就必须投向鸽子。

Bird pigeon = new Bird();会给出相同的输出吗? Dove pigeon = new Dove();怎么样?

+0

任何类都可以使用'super'关键字明确调用其父方法。 –

+0

我了解super关键字的功能。我的问题是为什么“鸽子”可以访问鸽子的方法。我认为“鸽鸽=新鸽”();“会产生“飞啁啾coo蹒跚”。 –

+0

提示:手动调用'pigeon.makeNoise()'并观察会发生什么。 – biziclop

回答

1

从你的问题后,“我认为,‘鸽子’只能访问鸟类可用的方法?我的印象是,如果用户想访问鸠方法, '鸽子'必须投给鸽子。“这实际上是true

让我们试着在理解中找到mssing链接。

  1. 当我们有一个像Bird pigeon = new Dove();代码,其中Dove延伸Bird我们有Dove实际对象和引用类型是Bird。由于目标是Dove所以它有方法,继承从超级以及增加

  2. 另一个重要的点是所有的overriden方法只有一个实例。它的Overriden意味着同一个方法的行为已被修改,它不是一个额外的单独方法。只有一个继承方法的副本不是两个。它的重载方法是分开的,只是名字相同但签名不同。这是您在调用任何重写方法时获得Dove行为的原因。

  3. 这一个很简单super,使用它的子类可以访问其超类的可访问(可见)实体(实例属性和方法)。如果子类使用super关键字来调用一个方法,那么它的被调用的父类的方法。但是可以认为,这个子类的作者也是故意的。一旦写入了类并且创建了此类的对象,然后在使用.(点运算符)的对象上,用户只能调用对象中的那些对象。如果有任何方法使用关键字super其对象的部分行为。 Sub类对象的用户如果在子类中重写它,则不能调用父类方法的行为。

  4. 最后是,如果你想使用Bird(超类)的参考,那么你需要将它转换为Dove调用Dove(子类)的任何其他方法。

4

长话短说,当您访问的pigeonact方法,从Dove它的覆盖被调用。

我以为'鸽子'只能访问Bird中可用的方法吗?

至少在没有应用铸造的情况下,这当然是正确的。然而,方法act可用于类Bird,这是静态已知类型的pigeon,因此调用编译良好。

但是,访问方法只是关于能够调用它们。当你打电话给他们时,什么方法是在运行时根据动态类型pigeon决定的。这是方法重写的地方,因为Dove覆盖Bird的方法,但此外它还调用Bird的方法。这就是为什么代码打到全部四个打印输出。

Bird pigeon = new Bird();会给出相同的输出吗?

否,则输出将是不同的,因为在这种情况下,动态和静态类型的pigeon将是相同的,即Bird,所以只有Bird的实施方式将被调用。

+5

这也是为什么你永远不能从构造函数调用overrideable方法的原因,因为子类可能会覆盖它,使得构造函数变得脆弱并且可能不安全。 – biziclop

2

你在这里遇到的是多态性在行动。而不是直接回答你的各种问题;我会简单解释你正在观察的情况。

您在Dove的实例上致电act();导致超级呼叫;印刷“飞”。

超级方法然后调用makeNoise() ...关于“本身”。但正如所说:“本身”是一个鸽子对象;因此你得到鸽子噪音! “COO”!

然后Dove实现结束;并打印“蹒跚”。

本质是:时调用在运行时被确定的方法的精确版本,它仅取决于确切类型的方法被调用的对象的。

上面给你全部你需要自己回答你的其他问题的信息。从这个意义上说:不要求答案;请求解释;并用它们来解决这个难题!

2
  • Dove确实覆盖方法actBirdmakeNoise。覆盖意味着将方法可见的的行为更改为子类(在您的情况下为Dove)。如果子类具有publicprotected访问修饰符,或者它们具有package private访问修饰符,并且子类与超类属于同一个包,则方法对子类可见。
  • pigeonDove的一个实例。
  • 致电pigeon.act()结果致电Dove.act
  • Dove.act来电super.act这是Bird.act
  • Bird.act打印fly并致电makeNoisepigeon导致致电Dove.makeNoise
  • Dove.makeNoise来电super.makeNoise这是Bird.makeNoise
  • Bird.makeNoise print chirp
  • Dove.makeNoise打印coo调用super.makeNoice
相关问题