5

考虑以下代码段:

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

在主要方法中,

 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()");
    }
  }

在主要方法中,

 new B();

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

4

2 回答 2

8

在执行构造函数 A 的代码时,它只能看到类 A 中的方法 m,因为尚未为类 B 初始化非静态成员(根据我提到的顺序)。

您假设方法是已初始化的“非静态成员”的一部分。情况并非如此 - 这实际上是在构造函数完成时初始化字段的问题。BA

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

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

于 2013-08-12T15:27:36.383 回答
3

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

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

于 2013-08-12T15:27:08.530 回答