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 innerYolk(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(){
innerYolk(new Yolk());
}
}
public static void main(String[] args) { Egg2 e = new BigEgg2();
        e.g();
}
}请问这会输出什么啊?
有人说 答案是   Egg2.Yolk()
new Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk().f()
不理解 请朋友帮忙解释解释! 谢谢了。

解决方案 »

  1.   

    类加载初始化先后顺序的问题 好像thinking in java 有一章把子类父类 变量构造函数的顺序都写得很清楚
      

  2.   

    我来编排下格式: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 innerYolk(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()
        {
            innerYolk(new Yolk());
        }    public static void main(String[] args)
        {
            Egg2 e = new BigEgg2();
            e.g();
        }
    }这样分析:我们从main方法开始看,首先是Egg2 e = new BigEgg2(); JVM首先要把Egg2加载进来,在加载该类时,会先按先变量后方法的顺序, 类Egg2中有这样一个变量定义private Yolk y = new Yolk();所以JVM在加载这个变量时,就调用了一下类 Yolk 的构造器,就首先打印了一句 Egg2.Yolk()。
    = 前面的Egg2加载完了,下面是要开始 = 后面了。在初始化子类的时候,父类的构造器会先被调用,所以,打印出了 new Egg2(),下面开始调用子类的构造器了。子类的构造器调用了一个方法,传给该方法的参数,是 new Yolk(),很显然,这个地方的 Yolk 是子类BigEgg2中新定义的 Yolk,这个新的 Yolk 继承自父类Egg2的 Yolk,所以,这里就要先调用下 Egg2 中的Yolk的构造器,打印出了Egg2.Yolk(),再打印出了BigEgg2.Yolk()。至于最后一行,为什打印出的是BigEgg2.Yolk().f()呢?因为 BigEgg2 的构造器调用了方法innerYolk(),该方法使得Egg2中变量y的值改变了,导致g()调用的是BigEgg2中Yolk的f()方法。
      

  3.   

    红字部分简直是一语惊人 非常感谢。
    如果我这样理解有错吗?
    首先是Egg2 e = new BigEgg2(); 在 new BigEgg2()时 先去new Egg2() 因为BigEgg2继承了Egg2,然后按照 先变量后方法的顺序,类Egg2中有这样一个变量定义private Yolk y = new Yolk();所以JVM在加载这个变量时,就调用了一下类 Yolk 的构造器,就首先打印了一句 Egg2.Yolk()。然后再调用自身的构造器(Egg2()) 打印了new Egg2() ,接着回到BigEgg2()的构造器,BigEgg2()构造器调用了一个方法,传给该方法的参数,是 new Yolk(),很显然,这个地方的 Yolk 是子类BigEgg2中新定义的 Yolk,这个新的 Yolk 继承自父类Egg2的 Yolk,所以,这里就要先调用下 Egg2 中的Yolk的构造器,打印出了Egg2.Yolk(),再打印出了BigEgg2.Yolk()。 因为 BigEgg2 的构造器调用了方法innerYolk(),该方法使得Egg2中变量y的值改变了,导致g()调用的是BigEgg2中Yolk的f()方法。
    我这样理解 完全跟 Egg2 e;没关系了 所有动作都发生在了 new 的一瞬间。请问有错吗? 谢谢指点。