一,类加载机制是什么?
将包含类数据的Class文件加载到内存,进行校验,解析,初始化之后,形成可被虚拟机直接使用的java类型;
主要内容:
①,全盘负责:当类加载器加载一个类时,这个类所依赖的引用的其他类都由同一个类加载器加载,除非显示使用其他类加载器加载
②,父类委托:先让父类加载器加载该类,如果父类无法加载,再尝试加载该类
③,缓存机制:加载过的class会被缓存起来,当使用class的时候先从缓存中查找,如果找不到系统才会读取类的二进制字节流,并将其转换为Class对象,存入缓存
(因此修改了类后需要重启JVM)
二,类的生命周期
1,加载:获取类的字节流,内存中创建java.lang.Class对象
2,验证: 对文件格式,元数据,字节码,符号引用验证
3,准备: 在方法区对静态变量分配内存,并设置初始零值
4,解析: 常量池中的符号引用转为直接引用
5,初始化: 再次初始化类变量和其他资源, 如静态变量设置正确的初始值
6,使用: 使用new出的对象在程序中的使用
7,卸载: 执行垃圾回收
这5个阶段是按照上面的顺序开始的,但是不一定按照上面的顺序进行或者完成,各个阶段相互交叉混合进行的,一个阶段执行过程中会激活其他阶段
其他扩展:
有且只有以下5种情况下发现有未初始化的类将会触发类的“初始化”: <------这5种行为引用类的方式称为:对类的"主动引用",其他引用类的方式被称为"被动引用"
【1】,①使用new实例化对象
②读取设置静态字段(static; 但是除外(final修饰已在编译期放入常量池的静态字段,本质上没有引用到定义常量的类))
③调用静态方法
【2】,使用反射(对类使用java.lang.reflect包的方法进行反射调用对应的类未初始化)
【3】,父类未初始化 (如果是接口:则只有真正使用到父类接口时才初始化,其他4中情况都相同)
【4】,虚拟机启动对主类初始化(包含main方法的类)
【5】,使用动态语言(如:使用JDK1.7动态语言,java.lang.invoke.MethodHandle实例后的REF_getStatic等方法句柄对应的类未初始化)
被动引用例子(一):
package com.classload.temp; /** * 父类 */ public class SuperClass {
//类使用static输出类的初始化信息; 接口由编译器自动生成<clinit>()类构造器,初始化接口的成员变量 static { System.out.println("SuperClass init ... ... "); } public static int value = 123; }
package com.classload.temp; /** * 子类 */ public class SubClass extends SuperClass { static { System.out.println("SubClass init ... ... "); } }
package com.classload.temp; public class MainTest { /** * 通过子类引用父类静态字段 * 子类不会初始化(不属于主动引用), * 父类进行初始化(属于主动引用: 符合主动引用第1,3条规则) */ public static void main(String[] args) { System.out.println(SubClass.value); } /** * 运行结果: * SuperClass init ... ... 123 */ }
被动引用例子(二):
package com.classload.temp; public class MainTest { /** * 通过数组定义引用类 * 不属于主动引用,类不会初始化 */ public static void main(String[] args) { SuperClass[] arr = new SuperClass[10]; }
//运行结果为空 }
被动引用例子(三):
package com.classload.temp; public class ConstClass { static { System.out.println("ConstClass init ... ... "); } //该静态常量在编译期存入常量池 public static final String HELLOWORLD = "hello world"; }
package com.classload.temp; public class MainTest { /** * 使用final修饰的静态常量 * HELLOWORLD常量在编译期存入了MainTest类常量池,不会初始化ConstClass类(不符合主动引用第1条规则) * 如果ConstClass.HELLOWORLD只使用static修饰(符合主动引用第1条规则属于主动引用)则会进行ConstClass类初始化 */ public static void main(String[] args) { System.out.println(ConstClass.HELLOWORLD); } }
参考:http://www.importnew.com/23742.html
参考:《深入理解Java虚拟机》