【问题标题】:Method overriding and Inheritance in javajava中的方法覆盖和继承
【发布时间】:2013-08-13 23:46:55
【问题描述】:

考虑以下代码段:

class A{ /* assume static and non static block are here */ }
class B extends A{ /* assume static and non static block are here */ }

在main方法中,

 new B();

所以初始化的顺序是:

  1. A 类的静态成员初始化
  2. B 类的静态成员初始化
  3. A 类的非静态成员初始化
  4. 然后执行构造函数A里面的代码
  5. B 类的非静态成员初始化
  6. 然后执行构造函数B中的代码

现在看看这段代码,

class A{
    A(){
        this.m(); //line 1
    }

    void m(){
        System.out.println("A.m()");
    }
  }

  class B extends A{
     void m(){
        System.out.println("B.m()");
    }
  }

在main方法中,

 new B();

在执行构造函数A的代​​码时,它只能看到类A中的方法m,因为类B的非静态成员还没有被初始化(按照我提到的顺序)。 然而结果是“B.m()”。 (子类的方法已经执行) 考虑到我提到的顺序,有人可以解释这里发生了什么(方法覆盖)吗?

【问题讨论】:

  • This 应该会带来一些清晰,尽管它不是完全重复的。
  • 你应该从不,从不,从不在构造函数/析构函数中调用虚方法。这是明确糟糕、糟糕的主意。调用final 实例方法可能是okay,但我通常认为这是一个bad 的想法,并尽可能避免它。这是一个非常可怕的想法,它在 Scott Meyer 的 Effective C++ 中有介绍,虽然您的问题 关于 Java,但他在此处给出的主要原因适用于此。不要这样做。
  • 另外你可能想通过Relevant JLS Section

标签: java overriding


【解决方案1】:

在执行构造函数A的代​​码时,只能看到A类中的方法m,因为B类的非静态成员还没有初始化(按照我提到的顺序)。

您假设方法是已初始化的“非静态成员”的一部分。事实并非如此——这实际上是B 中的字段A 构造函数完成时被初始化的问题。

一旦在 Java 中创建了一个对象,它的类型就会被设置并且永远不会改变。为所有字段分配了足够的空间 - 但这些字段实际上是从继承层次结构的顶部开始初始化

所以是的,如果你从构造函数中调用一个被覆盖的方法,它将在它想要使用的某些字段未初始化的上下文中执行 - 所以你应该尽可能避免这样做。

【讨论】:

  • 乔恩,有一个简短的问题,我想知道我是否朝着正确的方向前进;理解这一点的简单方法是,当我们有一个 B 类的实例时,它就是这里的活动对象。因此,new B() 将调用 A() 的超级构造函数,其中 this.m() 等效于 new B().m(),因为该方法已被覆盖。
  • @JNL:嗯,它并不等同于new B().m(),因为它不会创建新对象...
  • 乔恩,同意它不会创建一个新对象,我的意思是,如果我说得对,我可以说 this.m() 将等同于被称为 objectOfClassB.m()在 main 中,因为正在执行程序的主线程有一个 new B() 对象。我希望它不会令人困惑?
  • @JNL:嗯,我想是的 - 但我不确定它是否积极有帮助 :)
  • 只是想澄清一下。谢谢乔恩。欣赏它。
【解决方案2】:

无论派生类是否已初始化,都会发生方法覆盖。

这就是为什么你应该避免在初始化器中调用虚方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 1970-01-01
    • 2016-01-24
    • 1970-01-01
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多