初始化Sub类时Base类如何初始化

时间:2013-08-10 13:09:13

标签: java

代码是这样的:

class Base {
    int x = 10;

    public Base() {
        this.printMessage();
        x = 20;
    }

    public void printMessage() {
        System.out.println("Base.x = " + x);
    }
}

class Sub extends Base {
    int x = 30;

    public Sub() {
        this.printMessage();
        x = 40;
    }

    public void printMessage() {
        System.out.println("Sub.x = " + x);
    }
}

public class DispatchTest {
    public static void main(String[] args) {
        Base b = new Sub();
        System.out.println(b.x);
    }
}

结果是:

Sub.x = 0
Sub.x = 30
20

任何人都可以告诉我这段代码是如何运行的? 为什么Base类的costructor不运行?

4 个答案:

答案 0 :(得分:2)

因为您创建了一个新的Sub对象实例。类Sub覆盖了printMessage()方法,这意味着Base.printMethod()未被执行。

Base类的构造函数会运行,但this.printMessage()会从printMessage类执行Sub方法。

在调用Sub的构造函数之后,立即调用Base构造函数。它打印Sub.x = 0,因为到目前为止尚未设置x(在Sub中)。之后,值x被分配。

Base构造函数完成后,Sub构造函数的其余部分正在执行。它再次打印调用Sub的{​​{1}}方法,但这次值printMessage有一个值,并打印x

Sub.x = 30来自20

您可能想知道为什么在第一次System.out.println(b.x);通话期间未分配值x?由于您的printMessage课程中也有x,因此Sub课程中的x不可见!

答案 1 :(得分:1)

您的SuperClass构造函数始终被调用,但“访问被覆盖的成员变量时无法看到多态行为”。

  Base b = new Sub();
  System.out.println(b.x);

现在,如果你访问x(它存在于子类和超类中),它实际上是确定值的引用变量的类型。

注意:此行为与重写方法不同,在这种情况下,它实际上是确定要调用的方法而不是引用变量类型的对象类型。

答案 2 :(得分:1)

构造函数

    public Sub() {
        this.printMessage();
        x = 40;
    }

相当于

public Sub() {
        super();
        this.printMessage();
        x = 40;
}

所以当你创建

Base b = new Sub();

Base的构造函数被执行后跟Sub的构造函数。 See JLS 8.8.7,其中说明了

  

构造函数体的第一个语句可能是显式的   调用同一个类或直接的另一个构造函数   超


Base的构造函数正在printMessage()调用Sub 覆盖Base。当从printMessage()的构造函数x调用它时,会打印尚未初始化的Sub Sub.x = 0。这是一种反模式,因此x被打印(0尚未初始化,因此int的默认值为Bas


现在Sub e的构造函数完成后,x的构造函数被调用,现在30被初始化为class Sub extends Base { int x = 30; public Sub() { this.printMessage(); x = 40; } .... 为什么?

,因为

class Sub extends Base {
    int x;

    public Sub() {
        {
            x=30;
        }
        this.printMessage();
        x = 40;
    }
    ....

基本上意味着

printMessage()

因此这次Sub.x = 30打印20


最后打印{{1}}因为字段 未覆盖

答案 3 :(得分:0)

当我们创建子类对象时,将自动执行以下事件序列。

  

步骤1.从父到子识别实例成员并将它们初始化为默认值。

第一步后

  

基本实例变量是int x = 0;
  子实例变量是int x = 0;

     

步骤2.仅在父类中执行实例变量赋值和实例块

第二步后

  

基类实例变量是int x = 10;
  子类实例变量是int x = 0;

     

步骤3.执行父类构造函数。

第三步后

  

这里有一个“printMessage()”调用。它在子类Sub中被重写   因此Sub类方法执行并打印Sub类的变量x值,该值现在仅被指定为0   所以输出现在“Sub.x = 0”。   和基类int x = 20;   子类int x = 0;

     

步骤4.在子类中执行实例变量和实例块。

第4步后

  

基类int x = 20;   子类int x = 30;

     

步骤5.执行子构造函数。

第5步之后。

  

在Sub类构造函数中,您有“printMessage()”方法调用。因此它将执行并打印输出。
  所以输出现在“Sub.x = 30”   在方法调用之后,您有一个任务   所以现在基类int x = 20;   子类int x = 40;

现在您的Sub类构造函数已成功创建 现在你在类型引用“Base”上打印变量x的语句。现在,“Base”类变量x将作为输出打印。

  

所以输出是“20”。