1. 不涉及继承和多态的构造器初始化过程
当程序中出现new A a() , 或者使用了A类的静态方法等代码时(声明一个A类对象不算) java虚拟机会首先加载A类, 然后执行A的静态初始化, 静态初始化会先将所有的静态成员变量进行默认初始化, 也就是基本数据类型初始化为0, 引用数据类型初始化为null. 然后按照静态变量和静态区的初始化顺序和声明顺序一致这一准则进行初始化. 此时执行的静态初始化只执行这一次, 执行之后就再也不执行了.
然后如果出现new A a() , 就会为对象分配存储空间, 然后对所有的非静态成员变量进行默认初始化, 然后加载Object类(如果没有加载的话), 然后对Object对象进行初始化. 然后回到A类的内部, 按照成员变量和非静态区的声明顺序对其进行初始化. 最后执行构造函数, 完成初始化过程.
2. 一旦涉及到继承和多态, 初始化就变得稍微复杂了一点点.
涉及继承, 如果A类如果有一个或者多个父类的时候, 静态初始化的步骤不变, 但是当新建一个对象时 , 在默认初始化之后, 会一层一层地找父类, 直到Object类, 然后再向下依次初始化Object类和其他父类.
涉及多态, 如果父类的非静态代码块或者父类的构造函数中调用了涉及到多态的函数, 那么这个函数是A类相应重写的函数.
class Glyph { { draw() ; //会调用子类的 } void draw() { System.out.println("Glyph draw()") ; } public Glyph() { System.out.println("Glyph() before draw()") ; draw(); //会调用子类的 System.out.println("Glyph() after draw()") ; } } public class RoundGroph extends Glyph { private int radius = 1 ; RoundGroph(int i) { radius = i ; System.out.println("RoundGroph.Grougph().radius= " + radius) ; } void draw() { System.out.println("RoundGroph.draw().radius= " + radius) ; } public static void main(String args[]) { RoundGroph a = new RoundGroph(22) ; } }
之所以会出现这种情况是因为 动态绑定 . java之所以有多态, 就是由于<a href="http://www.cnblogs.com/yyyyy5101/archive/2011/08/02/2125324.html">动态绑定</a>.
上述代码就是对《thinking in java》这段话的一个解释
如果构造器只是在构建对象的一个步骤,并且 该对象所属的类 是从 这个构造函数所属的类 导出的,那么导出部分在当前构造器正在被调用的时刻仍然是没有初始化的。然而一个动态绑定的方法调用却会深入到继承层次结构的内部,调用导出类的方法。如果我们在构造函数中这么做,那么就可能调用某个方法,而这个方法所使用的成员可能还尚未初始化--这肯定会招灾引祸。
上面代码中的RoundGroph是Glyph的子类。按照上面对于有继承关系的初始化过程的描述,当遇到new RoundGroph(22),就会分配存储空间,并对RoundGroph的成员进行默认初始化,然后初始化他所持有的RoundGroph对象,在初始化Glyph的过程中会调用draw(),这个方法是动态绑定的,在RoundGroph还未完全初始化的情况下调用RoundGroph的draw(),如果此时draw()中使用了未初始化的子类成员变量,那么就会导致莫名的错误,也就是《thingking in java》中所说的招灾引祸。
//thinking in java笔记,如果有不对的地方,还望指正^_^