我有以下代码:
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:Egg2 e2 = new BigEgg2();
转到构造函数: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
Egg2.Yolk()
BigEgg2.Yolk
此阶段的外观如何?
为什么会这样?
最佳答案
用超类构造函数调用类的构造函数时,发生了很多事情,而且它们都具有实例变量初始化器。
您的BigEgg2
构造函数不会显式调用任何超类构造函数,因此编译器会插入对Egg2
的默认构造函数的调用。 (同样的情况适用于调用Egg2
构造函数的Object
构造函数,但该函数不会打印任何内容。)
对超类构造函数的调用完成后,将运行超类的实例初始化器(如果有)。这意味着任何实例变量都在声明它们的地方初始化。在这里,为实例变量Egg2.Yolk
创建了y
的实例。这是输出Egg2.Yolk()
的第一行。
然后,最终执行超类构造函数的主体。这是输出New Egg2()
的第二行。BigEgg2
类具有自己的Yolk
类,以实例化要在其自己的构造函数中传递给insertYolk
的情况。它创建一个Yolk
,该Yolk
在Egg2
中将嵌套类Egg2.Yolk
子类化。首先调用超类构造函数,该构造函数引用Egg2.Yolk()
类。这是输出BigEgg2.Yolk
的第三行。请注意,这是与输出的第一行相同的打印语句。
类y
的该对象在超类方法Egg2.insertYolk
中分配给实例变量BigEgg2.Yolk
。这发生在BigEgg2.Yolk
构造函数的主体中。 BigEgg2.Yolk
构造函数负责输出y
的第四行。请注意,BigEgg2.Yolk
变量现在引用的是main
的实例。至此,Egg2 e2 = new BigEgg2();
第一行的执行完成:e2.g()
。
调用g()
时,您正在调用BigEgg2
从Egg2
继承的y.f()
方法,该方法调用y
,其中Egg2.Yolk
是f()
。由于多态性,在BigEgg2.Yolk
中调用BigEgg2.Yolk.f()
方法。这是输出的第五行。