-1

代码是这样的:

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 的构造函数不运行?

4

4 回答 4

2

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

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

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

构造函数完成后Base,将执行构造函数的其余部分Sub。它再次打印调用Sub'sprintMessage方法,但这一次值x有一个值,并且它打印Sub.x = 30

20来自System.out.println(b.x);. _

您可能想知道,为什么在第一次调用x时没有分配值?printMessage因为你也有x你的Sub班级,所以x来自Base班级的人是不可见的!

于 2013-08-10T13:16:19.410 回答
1

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

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

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

注意:这种行为与被覆盖的方法不同,在这种情况下,实际上是对象的类型决定了要调用的方法,而不是引用变量的类型。

于 2013-08-10T13:19:33.953 回答
1

构造函数

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

相当于

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

所以当你创建

Base b = new Sub();

Base的构造函数被执行,然后是Sub的构造函数。请参阅 JLS 8.8.7,其中指出

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


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


现在一旦Base 的构造函数完成,Sub的构造函数被调用,现在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


finally20被打印,因为字段没有被覆盖

于 2013-08-10T13:25:06.770 回答
0

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

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

第一步之后

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

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

第二步之后

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

Step 3. 父类构造函数的执行。

第三步之后

这里有一个“printMessage()”调用。它在子类 Sub 中被覆盖,所以子类方法被执行并打印子类的变量 x 值,现在只分配为 0。
所以现在输出“Sub.x = 0”。和基类 int x = 20; 子类 int x = 0;

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

第四步之后

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

Step 5. 子构造函数的执行。

第五步之后。

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

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

所以输出是“20”。

于 2013-08-10T13:50:41.963 回答