Java类的初始化程序

晓得Java 类初始化过程有利于咱们对其运行过程的了解。
首先:每个类的编译代码都存在于它本人的独立的文件中,该文件只在须要应用程序代码时才会被加载。通常加载产生在创立类的第一个对象时或者该类的动态资源被拜访时。
另外,定义为static 类型的代码只会被初始化一次。
另外,结构器办法实际上是static的,是隐式的static申明。

首先说后果:
加载程序:该类的顶级父类的动态代码块 -> 顶级父类的动态成员变量 -> 父类的动态代码块 -> 父类的动态成员变量 -> ... -> 以后类的动态代码块 -> 以后类的动态成员变量 -> 顶级父类结构代码块初始化 -> ... -> 以后类结构代码块初始化 -> 顶级父类结构器初始化 -> ... -> 以后类结构器初始化 -> 运行业务代码...

一、动态资源被拜访时的加载的状况

package cn.tobin.cls;

class TestClassInitSuper {

private int i;protected int j;TestClassInitSuper() {    System.out.println("i : " + i + "; j : " + j);    System.out.println("TestClassInitSuper 结构器已运行");}{    i = 0;    j = 1;    System.out.println("TestClassInitSuper结构代码块已运行 ");}static {    System.out.println("TestClassInitSuper动态代码块已运行 ");}private static String SUPER_STATIC_STR = printStr("TestClassInitSuper.SUPER_STATIC_STR 已初始化");private static void parentStaticTest1() {    System.out.println("TestClassInitSuper parentStaticTest1静态方法已运行");}static String printStr(String str) {    System.out.println(str);    return str;}

}

public class TestClassInit extends TestClassInitSuper {

private int k = 2;private MemberObject member = new MemberObject();{    System.out.println("TestClassInit结构代码块已运行 ");}static {    System.out.println("TestClassInit动态代码块已运行 ");}public TestClassInit() {    System.out.println("TestClassInit.k : " + k);    System.out.println("TestClassInit 结构器已运行");}public static String STATIC_STR = printStr("TestClassInit 动态成员变量STATIC_STR已初始化");private static void subStaticTest1() {    System.out.println("TestClassInit subStaticTest1静态方法已运行");}public void test() {    System.out.println("test() 办法运行");}public static void main(String[] args) {    // 只调用动态资源    System.out.println("--- 只调用动态资源状况下的加载 ---");    System.out.println(TestClassInit.STATIC_STR);    System.out.println("--- 第二次加载TestClassInit ---");    System.out.println(TestClassInit.STATIC_STR);    System.out.println("--- 调用实现 ---");}

}

package cn.tobin.cls;

public class MemberObject {

public MemberObject() {    System.out.println("初始化了援用成员对象 MemberObject");}

}

再创立一个类独自用于测试:

package cn.tobin.cls;

public class TestInit {

public static void main(String[] args) {    // 只调用动态资源    System.out.println("--- 只调用动态资源状况下的加载 ---");    System.out.println(TestClassInit.STATIC_STR);    System.out.println("--- 第二次加载TestClassInit ---");    System.out.println(TestClassInit.STATIC_STR);    System.out.println("--- 调用实现 ---");}

}

运行后果:

--- 只调用动态资源状况下的加载 ---
TestClassInitSuper动态代码块已运行
TestClassInitSuper.SUPER_STATIC_STR 已初始化
TestClassInit动态代码块已运行
TestClassInit 动态成员变量STATIC_STR已初始化
TestClassInit 动态成员变量STATIC_STR已初始化
--- 第二次加载TestClassInit ---
TestClassInit 动态成员变量STATIC_STR已初始化
--- 调用实现 ---

Process finished with exit code 0

在这个测试中,如果把该main 办法写在TestClassInit类中,后果就可能不太一样了:

TestClassInitSuper动态代码块已运行
TestClassInitSuper.SUPER_STATIC_STR 已初始化
TestClassInit动态代码块已运行
TestClassInit 动态成员变量STATIC_STR已初始化
--- 只调用动态资源状况下的加载 ---
TestClassInit 动态成员变量STATIC_STR已初始化
--- 第二次加载TestClassInit ---
TestClassInit 动态成员变量STATIC_STR已初始化
--- 调用实现 ---

Process finished with exit code 0

起因很简略,在加载到main办法之前,以后类(TestClassInit)首先被加载,而后再执行main 办法。

二、创建对象时的加载程序
再创立一个类独自测试,第一次创建对象和第二次创建对象的状况:
package cn.tobin.cls;

public class TestInit2 {

public static void main(String[] args) {    TestClassInit testObject = new TestClassInit();    testObject.test();    System.out.println("--- 第二次加载TestClassInit ---");    TestClassInit testObject2 = new TestClassInit();    testObject2.test();}

}

运行后果:

TestClassInitSuper动态代码块已运行
TestClassInitSuper.SUPER_STATIC_STR 已初始化
TestClassInit动态代码块已运行
TestClassInit 动态成员变量STATIC_STR已初始化
TestClassInitSuper结构代码块已运行
i : 0; j : 1
TestClassInitSuper 结构器已运行
初始化了援用成员对象 MemberObject
TestClassInit结构代码块已运行
TestClassInit.k : 2
TestClassInit 结构器已运行
test() 办法运行
--- 第二次加载TestClassInit ---
TestClassInitSuper结构代码块已运行
i : 0; j : 1
TestClassInitSuper 结构器已运行
初始化了援用成员对象 MemberObject
TestClassInit结构代码块已运行
TestClassInit.k : 2
TestClassInit 结构器已运行
test() 办法运行

Process finished with exit code 0

阐明:父类优于基类优先初始化,每个类外部动态代码块,动态成员都只初始化一次,类中成员变量优于结构代码块,结构器之前,动态初始化之后初始化,并且每次加载都从新初始化一次。