类别基础:
public class Base {
private String name = "base";
public Base() {
tellName();
printName(name);
}
public void tellName() {
System.out.println("Base tell name:" + name);
}
public void printName(String name) {
System.out.println("Base print name:" + name);
}
}
类派生:
public class Derived extends Base {
private String name = "Derived";
public Derived() {
tellName();
printName(name);
}
public void tellName() {
System.out.println("Derived tell name:" + name);
}
public void printName(String name) {
System.out.println("Derived print name:" + name);
}
public static void main(String[] args) {
Derived derived = new Derived();
}
}
结果:
Derived tell name:null
Derived print name:base
Derived tell name:Derived
Derived print name:Derived
最近,我被问到这个问题。我想到了,但没有确切的答案为什么这个程序部分有这样的执行结果。 希望有人能帮我分析这样的问题。非常感谢! ^ - ^
我只想知道派生条件下构造函数的执行过程。
答案 0 :(得分:2)
根本不应该有任何混淆。无论何时调用构造函数,它都将调用父类构造函数。因此,当您构造Derived实例时,它将隐式调用Base类构造函数。这会将成员变量'name'设置为基本实例中的值'base'。之后,在基础构造函数中调用方法tellName()
和printName()
,这实际上将调用实际实例上的方法。即派生实例。此时,Derived实例中的成员变量“name”为null,这就是您看到Derived tell name:null
的原因。之后,当通过在基本实例中传递'name'成员变量来调用方法printName时,这只是传递给Derived实例中的方法。这就是Derived print name:base
的原因。完成父构造函数后,Derived实例中的成员变量'name'将设置为值'Derived',然后它将在Derived实例上调用tellName()和printName(name)。所以,这就是为什么我们看到接下来的两行输出
Derived tell name:Derived
Derived print name:Derived
这背后的故事很长!
答案 1 :(得分:0)
执行从Derived.main
开始。这将创建Derived
的新实例,因此将调用Derived
构造函数。首先调用Base
构造函数,该构造函数初始化Base
子对象的name
,然后调用tellName
。由于动态调度,调用的tellName
为Derived.tellName
而非Base.tellName
。此打印的文本引用尚未初始化的Derived
子对象的name
,而不是已初始化的Base
子对象的name
,因此打印"Derived tell name:null"
。控件将在Base
构造函数中继续,然后使用printName
子对象的Base
调用name
。由于动态调度,会调用Derived.printName
。它打印的name
是它的参数,(正如我们刚才看到的)是来自name
子对象的Base
。因此,它打印"Derived print name:base"
,因为Base
子对象的name
之前已初始化为"base"
。 Base
构造函数现已完成,控件将在Derived
构造函数中恢复。现在,这会将Derived
子对象的name
初始化为"Derived"
,然后以明显的方式调用Derived.tellName
和Derived.printName
,并观察结果。
作为一个额外的观察,值得注意的是,这里出现的问题是因为Java在构造函数中动态调度虚拟调用;其他语言如C ++不会,例如见:
http://www.parashift.com/c++-faq-lite/calling-virtuals-from-ctors.html