这种输出"println"顺序的原因是什么?如何初始化此代码中的对象?



我有这个代码:

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()

问题:现在我无法弄清楚这些对象和类是如何初始化的。 我认为顺序应该是这样的:

  1. 创建新链接 e2: 蛋2 e2 = 新的大蛋2();

  2. 转到构造函数: public BigEgg2() { insertYolk(new Yolk()); }

  3. 由于继承编译器转到:public Yolk() { System.out.println("Egg2.Yolk()");},之后我们看到输出:Egg2.Yolk();

  4. 然后编译器调用了这个方法:public void insertYolk(Yolk yy) { y = yy; },其中 Egg2.Yolk.y = BigEgg2.Yolk.yy(形象地说)。

  5. 在此步骤中,我无法弄清楚为什么下一个输出结果将是:

    新蛋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继承自Egg2g()方法,该方法调用y.f(),其中y是一个Egg2.Yolk。 由于多态性,BigEgg2.Yolk中的f()方法被称为。 这是输出BigEgg2.Yolk.f()的第五行。

最新更新