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