代码是这样的:
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不运行?
答案 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”。