由于Java中的所有事物都是对象, 所以许多动作就变得更加容易, 加载动作仅仅是其中之一.
Java中每个类的编译代码都存在于它自己的独立的文件中. 该文件只在需要使用程序代码时才会被加载. 可以说:"类的代码在初次使用时才加载". 这通常是指直到类的第一个对象被构建时才发生加载, 但是当访问static字段方法时, 其也会发生加载.
初次使用之处也是static初始化发生之处. 所有的static对象和static代码段都会在加载时依程序中的顺序(即定义类时的书写顺序)而依次初始化. 当然, 定义为static的东西只会被初始化一次.
* Title: The full process of initialization<br>
* Description: 了解包括Inheritance在内的初始化全过程, 以对所发生的一切有个全局性的把握<br>
* Copyright: (c) 2008 Thinking in Java<br>
* Company: Augmentum Inc<br>
* @author Forest He
* @version 1.0
*/
class Insect ... {
private int i = 9;
protected int j;
Insect() ...{
System.out.println("i=" + i + ",j=" + j);
j=37;
}
private static int x1 = print("static Insect.x1.initialized");
public static int print(String s) ...{
System.out.println(s);
return 47;
}
}
class Bettle extends Insect ... {
private int k = print("Bettle.k initialized");
public Bettle() ...{
System.out.println("k=" + k);
System.out.println("j=" + j);
}
private static int x2=print("static Bettle.x2 initialized");
public static void main(String [] args) ...{
System.out.println("Bettle constructor");
Bettle b = new Bettle();
}
}
上例中, 在Beetle上运行Java时, 所发生的第一件事就是试图访问Beetle.main()(一个static方法), 于是加载器开始启动并找出Beetle类的编译代码(它被编译到了一个名为Beetle.class的文件中). 在对Beetle进行加载的过程中, 编译器注意到它有一个基类(这是由extends关键字得知的), 于是Beetle继续进行加载(对基类加载). 不管你是否打算产生一个该基类的对象, 这都要发生.
如果该基类还有其自身的基类, 那么第二个基类就会被加载, 如此类推. 接下来, 根基类中的static初始化(在此例中为Insect)即会被执行, 然后是下一个导出类, 依次类推. 这种方式很重要, 因为导出类的static初始化可能会依赖于基类成员能否被正确初始化.
至此为止, 必要的类都已加载完毕, 对象就可以被创建了. 首先, 基类对象中的所有基本类型和对象都会被设为缺省值; 然后, 基类Constructor会被调用(自动调用or人工通过super()调用). 在基类Constructor完成之后, 导出类成员按其次序被初始化, 最后导出类Constructor执行.