我有这个代码:
class Egg2 {
protected class Yolk {
public Yolk() { System.out.println("Egg2.Yolk()");}
public void f() { System.out.println("Egg2.Yolk.f()"); }
}
private Yolk y = new Yolk();
public Egg2() { System.out.println("New Egg2()");}
public void insertYolk(Yolk yy) { y = yy; }
public void g() { y.f(); }
}
public class BigEgg2 extends Egg2 {
public class Yolk extends Egg2.Yolk {
public Yolk() { System.out.println("BigEgg2.Yolk"); }
public void f() { System.out.println("BigEgg2.Yolk.f()"); }
}
public BigEgg2() { insertYolk(new Yolk()); }
public static void main(String[] args) {
Egg2 e2 = new BigEgg2();
e2.g();
}
}
输出为:
Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk
BigEgg2.Yolk.f()
问题:现在我无法弄清楚这些对象和类是如何初始化的。 我认为顺序应该是这样的:
创建新链接 e2: 蛋2 e2 = 新的大蛋2();
转到构造函数: public BigEgg2() { insertYolk(new Yolk()); }
由于继承编译器转到:public Yolk() { System.out.println("Egg2.Yolk()");},之后我们看到输出:Egg2.Yolk();
然后编译器调用了这个方法:public void insertYolk(Yolk yy) { y = yy; },其中 Egg2.Yolk.y = BigEgg2.Yolk.yy(形象地说)。
在此步骤中,我无法弄清楚为什么下一个输出结果将是:
新蛋2()
蛋2.蛋黄()
大蛋2.蛋黄
现阶段是什么样子?
为什么会这样?
当您使用超类构造函数调用类的构造函数时,会发生很多事情,并且它们都具有实例变量初始值设定项。
BigEgg2
的构造函数不会显式调用任何超类构造函数,因此编译器插入了对Egg2
的默认构造函数的调用。 (同样的事情适用于调用Object
构造函数的Egg2
构造函数,但该构造函数不打印任何内容。
对超类构造函数的调用完成后,将运行超类的实例初始值设定项(如果有)。 这意味着任何实例变量在声明它们的位置初始化。 在这里,为实例变量y
创建Egg2.Yolk
的实例。 这是输出Egg2.Yolk()
的第一行。
然后最终执行超类构造函数的主体。 这是输出New Egg2()
的第二行。
BigEgg2
类有自己的Yolk
类,用于实例化以传递给自己的构造函数中的insertYolk
。 它创建一个Yolk
,该在Egg2
中对嵌套类Yolk
进行子类化。 超类构造函数称为 first,它指的是Egg2.Yolk
类。 这是输出Egg2.Yolk()
的第三行。 请注意,这是与输出的第一行相同的打印语句。
类BigEgg2.Yolk
的此对象被分配给超类方法Egg2.insertYolk
中的实例变量y
。 这发生在BigEgg2.Yolk
构造函数的主体中。BigEgg2.Yolk
构造函数负责输出BigEgg2.Yolk
的第四行。 请注意,y
变量现在引用BigEgg2.Yolk
的实例。 此时,main
第一行的执行完成:Egg2 e2 = new BigEgg2();
。
当你调用e2.g()
时,你正在调用BigEgg2
继承自Egg2
的g()
方法,该方法调用y.f()
,其中y
是一个Egg2.Yolk
。 由于多态性,BigEgg2.Yolk
中的f()
方法被称为。 这是输出BigEgg2.Yolk.f()
的第五行。