本次内容见java编程思想384页Egg2()
外围类BigEgg2继承了外围类Egg2,且BigEgg2的内部类Yolk明确继承了Egg2的内部类Egg.Yolk之后,会出现什么情况?
package BigEgg; 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(); { System.out.println("New Yolk2()"); } public Egg2() { System.out.println("New Egg2()"); } //private Yolk y1 = new Yolk(); protected void insertYolk(Yolk yy) { y = yy; } public void g() { y.f(); } } public class BigEgg2 extends Egg2 { public class Yolk extends Egg2.Yolk { //通过继承明确的继承了Egg2.Yolk类,并覆盖了其中的方法 public Yolk() { System.out.println("BigEgg2.Yolk()"); } public void f() { System.out.println("BigEgg2.Yolk.f()"); } } //private Yolk y3 = new Yolk(); public BigEgg2() { insertYolk(new Yolk()); }//向上转型成Egg2.Yolk类 public static void main(String[] args) { Egg2 e2 = new BigEgg2(); e2.g(); } }
输出结果为
Egg2.Yolk()
New Yolk2()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()
现在来看一下这些结果的执行顺序:
首先调用new BigEgg2()的时候,首先会隐式调用父类Egg2的构造器,调用父类构造器之前,父类所有的数据域都会初始化为默认值,然后按顺序调用构造代码块,最后调用构造器。
这里面,父类的私有域y被显式初始化为new Yolk(),显式初始化语句是最开始被执行的,所以父类的内部类的构造器会第一个被执行,输出"Egg2.Yolk()"。执行完显式初始化语句后是构造代码块,输出"New Yolk2()",
最后才是父类的构造器,输出"New Egg2"。
接下来执行子类的构造器代码,此时已经创建了一个BigEgg2类型的对象,y还是从父类继承下来的,在执行insertYolk方法前应该指向的是父类中的Yolk类型。insertYolk方法是将类的数据域y指向传入它的参数,一个Yolk类型的对象,相当于给数据域赋值。
执行new Yolk(),因为BigEgg2中的内部类是Egg2中内部类Yolk的子类,所以先执行父类的构造器,再执行被覆写的子类的构造器,分别输出"Egg2.Yolk()"和"BigEgg2.Yolk()"。