日期:2014-05-20  浏览次数:20865 次

关于构造方法的调用问题
现在这样一个问题,不明白想请会的讲解下,问题如下:
现有三个类: 一个Father类,一个Son类,继承Father类,一个测试类Test,代码如下:
public class Father {
public int value=100; // 这里为1
public Father(){ // 这里为2
int i=20; // 这里为3
System.out.println(i); // 这里为4
}
}

public class Son extends Father {
public int id=200; // 这里为5
public Son(){ // 这里为6
int j=10; // 这里为7
System.out.println(j); // 这里为8
}
}

public class Test{
  public static void main(String[] args){
  Father f=new Son(); // 这里为9
  }
}

现在我在Test中的主方法main那里设置断点:用debug as 调试,只按F5,
我想问下为什么执行顺序会是:9→6→2→1→3→4→5→7→8→9
请各位大神级人物讲解下,尤其为什么有1与5这两个步骤,还有从9到6再到2,好像没有进入构造方法内部,这样子调用起什么作用,或者有什么含义?

------解决方案--------------------
尤其为什么有1与5这两个步骤?
因为在构造方法执行前要初始化成员变量
9到6再到2
在执行子类构造方法前得先执行父类构造方法
------解决方案--------------------
6和2表示生成对象需要调用构造方法,6->2的顺序表示调用子类构造方法之前会先跳转去调用父类的构造方法
1和5表示在构造方法执行之前会先执行初始化块处理
int value = 100;
相当于
int value;
{value = 100;} //初始化块

给LZ个例子
Java code
class A {
    {System.out.println("1");} //初始化块
    public A() {
        System.out.println("2");
    }
}

public class B extends A {
    {System.out.println("3");} //初始化块
    public B () {
        System.out.println("4");
    }

    public static void main(String[] args) {
        new B();
    }
}

------解决方案--------------------
继承的实例类加载器的执行过程如下:
1. ClassLoader加载Son这个类. 
2. 准备调用Son的构造方法. 
3. 准备调用Son的父类Father的构造方法.
4. 准备调用Father的父类java.lang.Object的构造方法. 
5. 执行java.lang.Object的构造方法. 
6. 初始化Father类的成员变量
7. 执行Father的构造方法,
8. 初始化Son的成员变量
9. 执行Son的构造方法
 
------解决方案--------------------
为什么有1与5这两个步骤?因为在构造方法执行前要初始化成员变量.

从9到6再到2,好像没有进入构造方法内部,这样子调用起什么作用,因为在子类的构造方法Son()里面第一行,默认是调用父类的空构造方法super(),只是隐式调用而已. 



------解决方案--------------------
继承的实例类加载器的执行过程如下:
1. ClassLoader加载Son这个类. ---因为Test是启动类 ,所以jvm会先加载Test类,执行main方法 9
2. 准备调用Son的构造方法. 3. 准备调用Son的父类Father的构造方法.
4. 准备调用Father的父类java.lang.Object的构造方法. 
5. 执行java.lang.Object的构造方法. 
6. 初始化Father类的成员变量
7. 执行Father的构造……

---因为Test是启动类 ,所以jvm会先加载Test类,执行main方法 9
---创建Son对象 ,所以 6
---由于Son继承自 Father,所以在进入Son构造方法时 ,会先调用父类的构造方法 ,完成父类中定义的变量初始化 ,否则子类无法使用父类中的属性方法 2
---初始化一个类时(指的是创建一个类的对象,不是类加载),会先执行为非静态变量分配内存 ,执行顺序为非静态变量在类中定义的顺序 ,执行非静态代码块 即{}中的代码 ;所以 1
---执行完非静态变量分配内存及初始化值后,接着执行 构造函数中的代码 3 4

---完成父类的初始化后 ,接着执行Son构造方法,在执行之前类似于父类初始化 ,先初始化非静态变量分配内存,执行非静态代码块 5
---然后执行Son构造函数体 7 8
9-6-2-1-3-4-5-7 -8