- 相关知识
根据《Java编程思想》中的介绍,类是在其任何static成员被访问时加载的。构造器也是static方法,只是static关键字没有显示地写出来。
和C语言程序一样,Java应用程序的入口函数也是main,由于JVM在运行这个Java应用程序的时候,首先会调用main方法,调用时不实例化这个类的对象,而是通过类名直接调用因此需要是限制为public static。对于Java中的main方法,JVM有限制,不能有返回值,因此返回值类型为void。
在类的内部,变量的定义在任何方法(包括构造器)被调用之前得到初始化。
import static my.tool.Print.*; class A { static int j = printInit("A.j initialized"); static int printInit(String s) { print(s); return 1; } A() { print("A() constructor"); } public String toString() { return "print A"; } } class B extends A { static int k = printInit("B.k initialized"); B() { print("B() constructor"); } } class C { static int n = printInitC("C.n initialized"); static A a = new A(); static int printInitC(String s) { print(s); return 1; } } class D { D() { print("D() constructor"); } } public class Demo extends B { static int i = printInit("Demo.i initialized"); Demo() { print("Demo() constructor"); } public static void main(String[] args) { print("hi"); print(C.a); D d = new D(); } }Java程序的每个文件中,每一个类会生成一个class文件。上面的程序生成的文件如下所 示,
然后在需要类的时候进行加载,先看看上面程序的运行结果:
过程:JVM首先找到应用程序的入口函数main,又因为Demo类是从B类继承过来的,就加载B类,然后B又是从A继承过来的,接着加载A类。A没有基类于是A类中的static初始化被执行,然后是导出类,以此往下执行。接着执行main函数中的第一行,打印出"hi"字符串。然后是打印C类中的静态成员a,引起加载C类,执行static初始化,这里新建了一个A类对象所以调用A类的构造器。最后是新建一个D类的对象,加载D类,调用D类的构造器。
个人理解总结(望指正):从C类中的静态A类对象可以看出,这个时候要创建一个A类的对象,但是这里只显示调用了A类的构造函数,所以我们可以知道加载类的动作只执行了一次。刚开始Demo、A、B类的加载说明了对static成员的访问会引起加载,然后D类对象的创建说明了该类的第一个实体的创建会引起加载。
参考资料:http://lavasoft.blog.51cto.com/62575/53263/