【问题标题】:why methods inside parent constructor actually invoke child method为什么父构造函数中的方法实际上调用子方法
【发布时间】:2015-11-30 04:15:17
【问题描述】:
 class Glyph {
      void draw() {
        System.out.println("glyph.draw()");
      }

    Glyph() {
        System.out.println("glyph() before draw");
        draw();
        System.out.println("glyph() after draw");
    }
 }

 class RoundGlyph extends Glyph {
    private int radius = 1;

    RoundGlyph(int r) {
        radius = r;
        System.out.println("roundGlyph.RoundGlyph:" + radius);
    }

    @Override
    void draw() {
        System.out.println("roundGlyph.draw:" + radius);
    }
}

public class PolyConstructors {
    public static void main(String[] args) {
      new RoundGlyph(3);
    } 
}

输出是:

glyph() before draw
**roundGlyph.draw:0**
glyph() after draw
roundGlyph.RoundGlyph:3

我对第二个结果感到困惑,为什么父类构造函数中的代码draw(),实际上调用了子draw方法而不是父draw方法?

【问题讨论】:

  • 继承是这样工作的
  • @MadProgrammer 除了它不是 C++ 中的继承方式。
  • @MichaelAnderson 好吧,当 OP 发布有关 C++ 的问题时,我一定会记住它;)
  • 如果您创建Glyph (new Glyph()) 的对象,那么它的Glyph.draw() 方法将被调用。如果您创建RoundGlyph 的对象,那么它的RoundGlyph.draw() 方法将被调用。
  • 所以每次我用new RoundGlyph() 初始化RoundGlyph对象时,它是否会初始化Glyph对象

标签: java methods constructor polymorphism


【解决方案1】:

所以 draw() 调用正在调用 this.draw() 其中 this 是您的实例化对象。

在这种情况下,this 指的是 RoundGlyph 类型的对象,该对象已覆盖 Draw() 方法。在RoundGlyph 对象的上下文中,没有打印"glyph.draw()" 的Draw 方法,那就没有了。

【讨论】:

    【解决方案2】:

    发生这种情况是因为覆盖。

    什么是压倒一切的?

    在面向对象的编程中,方法覆盖是一种语言功能,它允许子类或子类提供已由其超类或父类之一提供的方法的特定实现。子类中的实现通过提供与父类中的方法具有相同名称、相同参数或签名以及相同返回类型的方法来覆盖(替换)超类中的实现。

    如何决定执行哪个方法?

    执行的方法的版本将由用于调用它的对象确定。

    请注意,对象决定调用哪个方法。


    在您的情况下,当调用 draw() 时使用 RoundGlyph 的对象。由于类RoundGlyph 覆盖了draw 函数,因此调用了RoundGlyph 中的draw。

    如需进一步阅读,请参阅this 和this

    【讨论】:

    • 所以每次我用new RoundGlyph() 初始化RoundGlyph 对象时,也是初始化Glyph 对象。
    • @side 是的,在构造派生类对象时,也会构造基类。阅读更多关于继承here
    • @side 有关更多信息,请参阅this。
    【解决方案3】:

    每当您创建子类对象时,都会调用父调用的默认构造函数,然后调用子类构造函数。并且方法调用是在运行时确定的,它取决于正在创建的对象。

    如果您创建Glyph (new Glyph()) 的对象,则将调用其Glyph.draw() 方法。如果您创建RoundGlyph 的对象,那么它的RoundGlyph.draw() 方法将被调用。

    如果你想从子类重写方法调用父类方法,那么你必须从子类方法显式调用(使用super关键字)它。

    @Override
    void draw() {
        super.draw();
        System.out.println("roundGlyph.draw:" + radius);
    }
    

    更详细的解释和例子请参考inheritance documentation。

    【讨论】:

    • 所以每次我用 new RoundGlyph() 初始化 RoundGlyph 对象时,是否会初始化 Glyph 对象
    • 你可以这样想,继承就是继承超类的属性和方法,同时增加一些新的功能。您可以看到初始化子类对象时如何调用超类默认构造函数。
    • @side,我添加了 inheritance 和 super 关键字的文档链接。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    • 2016-05-27
    • 2011-02-07
    • 1970-01-01
    • 2018-03-17
    • 1970-01-01
    相关资源
    最近更新 更多