简述:
看了《深入Java虚拟机》一书中关于“类是否初始化?“ 这一问题的探讨后,觉得有必要亲手做下总结
在实际代码中, 有些类可能看上去时初始化了,但实际上并没有。
举个例子,
对于一个类Fruit, 声明一个fruit[] 数组,看上去是很多个Fruit对象被初始化了,其实一个都没有,下面就竟可能全面的讨论一下这个问题
检测方式
在类里加一个静态区域,如果类初始化,那么这段静态区域就会有输出
生成这4条指令的几个最常见的Java代码场景是:
package test.class_life_cycle.initialize; class T{ //when initialize the class T, then will come the output static{ System.out.println("Initialize class T"); } } public class Test0 { public static void main(String[] args) { T t = new T(); } }
输出:
package test.class_life_cycle.initialize; class A{ static final int count = 1; //When call the class , this part is the first to execute static{ System.out.println("Initialize class A"); } } class Test1{ public static void main(String[] args) { int x = A.count; } }
但是没有任何输出,就是因为 那个final字段,Java编译器把这样的字段解析成对常量的本地拷贝(该常量存在于引用者类,这里就是Test1类 的常量池里或者字节码里)
package test.class_life_cycle.initialize; class X{ static void Output(){ System.out.println("Output !"); } //When call the class , this part is the first to execute static{ System.out.println("Initialize class X"); } } public class Test1_3 { public static void main(String[] args) { X.Output(); } }
输出:
通过调用java.lang.Class.forName(String className)
package test.class_life_cycle.initialize; class B{ static final int count = 1; //When call the class , this part is the first to execute static{ System.out.println("Initialize class B"); } } public class Test2 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { Class classB = Class.forName("test.class_life_cycle.initialize.B"); } }
而且由下面的输出顺序可以看到先初始化父类,再是子类的
package test.class_life_cycle.initialize; class Cfather{ static{ System.out.println("Initialize class Cfather"); } } class Cson extends Cfather{ static{ System.out.println("Initialize class Cson"); } } public class Test3 { public static void main(String[] args) { Cson son = new Cson(); } }
其实就是public static void main(String[] args)所在的那个类
下面这个例子中,虽然是以Dson.count 形式调用的,但是因为count是Dfather的静态成员变量,所以只初始化Dfather类,而不初始化Dson类
package test.class_life_cycle.initialize; class Dfather{ static int count = 1; static{ System.out.println("Initialize class Dfather"); } } class Dson extends Dfather{ static{ System.out.println("Initialize class Dson"); } } public class Test4 { public static void main(String[] args) { int x = Dson.count; } }
package test.class_life_cycle.initialize; class E{ static{ System.out.println("Initialize class E"); } } public class Test5 { public static void main(String[] args) { E[] e = new E[10]; } }
但是没有输出
package test.class_life_cycle.initialize; class F{ static final int count = 1; static{ System.out.println("Initialize class F"); } } public class Test6 { public static void main(String[] args) { int x = F.count; } }
如上例中,F类中定义的count是final对象,其在编译阶段就会存入调用类的常量池中