class superclass {
superclass() {
show();
}
void show() {
System.out.println("three");
}
}
class subclass extends superclass {
int x=3;
void show() {
System.out.println(x);
}
public static void main(String ar[]) {
subclass s=new subclass();
}
}
输出:0
据我说:首先执行子类构造函数,然后调用超类构造函数。这意味着,首先,超类的show()
方法应该执行并且应该打印three
,但这不会发生。为什么呢?
答案 0 :(得分:4)
在初始化任何子类变量之前执行超类构造函数。因此,当subclass
构造函数正在执行时,x
中的x
仍为subclass
(默认值)。当在构造函数中调用方法时,多态性仍然有效,因此调用0
的{{1}},打印superclass
打印subclass
。这说明了在构造函数中调用可覆盖方法的危险 - 变量可能尚未初始化。在这种情况下,show
不是x
[尚未。
JLS, Section 12.5,涵盖了执行构造函数的步骤。
在作为结果返回对新创建的对象的引用之前,处理指示的构造函数以使用以下过程初始化新对象:
将构造函数的参数分配给此构造函数调用的新创建的参数变量。
如果此构造函数以同一个类中的另一个构造函数的显式构造函数调用(第8.8.7.1节)开头(使用此方法),则使用这五个相同步骤计算参数并以递归方式处理该构造函数调用。如果该构造函数调用突然完成,则此过程突然完成,原因相同;否则,继续步骤5.
此构造函数不以同一类中另一个构造函数的显式构造函数调用开头(使用此方法)。如果此构造函数用于Object以外的类,则此构造函数将以超类构造函数的显式或隐式调用开始(使用super)。使用这五个相同的步骤评估参数并递归处理超类构造函数调用。如果该构造函数调用突然完成,则此过程突然完成,原因相同。否则,请继续执行步骤4.
为此类执行实例初始值设定项和实例变量初始值设定项,将实例变量初始值设定项的值分配给相应的实例变量,按从而出现的从左到右的顺序在文本的源代码中。如果执行任何这些初始值设定项导致异常,则不会处理其他初始化程序,并且此过程会突然完成同样的异常。否则,请继续步骤5.
- 醇>
执行此构造函数的其余部分。如果执行突然完成,则此过程突然完成,原因相同。否则,此过程正常完成。
(强调我的)
在调用超类构造函数完成后,无论该调用是显式调用还是隐式调用,都会初始化变量。
答案 1 :(得分:2)
subclass
会覆盖superclass
的{{1}}方法。因此,当您创建show
的实例时,会执行subclass
的{{1}}方法。
它返回subclass
而不是show
的原因是它是从0
的构造函数调用的,它是在3
的实例变量初始化之前执行的。因此superclass
仍包含默认值0。
答案 2 :(得分:1)
正如我上次发布此问题所述,当您创建subclass
对象时,它调用superclass
构造函数调用子show()
方法(覆盖超级{{ {1}}方法)之前 x初始化为3。
如果你有
show()
在你的子类中,然后它会打印subclass(){
show();
}
因为在x被初始化为该值之后会调用show()方法。
如果您想打印3
,那么您应该在子类构造函数中调用three
。