JAVA-类加载机制(1)-生命周期

一,类加载机制是什么?

将包含类数据的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虚拟机》

原文地址:https://www.cnblogs.com/wanhua-wu/p/6557576.html