JVM类加载机制(一)

时间:2020-03-16 16:13:03   收藏:0   阅读:78

一、概念

  程序编译后,生成class文件,经过加载、验证、准备、解析、初始化,最终使程序可以被JVM识别。

二、类的生命周期

  类从被加载到虚拟机内存开始,到卸载出虚拟机内存结束,一共经历加载、验证、准备、解析、初始化、使用、卸载七个阶段。

其中验证、准备、解析统称为连接。

  借用网上的图:

技术分享图片

 

  其中解析过程在某些情况下可以在初始化之后执行,这是为了支持JAVA的动态绑定。

三、类的初始化时机

  1. 使用new实例化对象

  2. 反射

  3. 初始化一个类时,发现父类没有被初始化,先初始化父类

  4. 指定要执行的主类包含main方法

  5. 使用JDK1.7的动态语言支持时,MethodHandle实例包含REF_get\put\invoke static句柄,且对应类未初始化

  以上场景行为称为对类的主动引用,而被动引用不会被初始化,包含以下几个场景:

  1. System.out.print(SubClass.value); // value的引用在父类SuperClass中

  2. SuperClass[] sca =new SuperClass[10]; // 数组类型不会触发类的初始化

    数组类型是jvm自动生成、继承Object的子类。

  3.System.out.print(Constants.HELLOWORLD); // 常量类在编译时将进入常量池,本质上不会调用Constants类的初始化。

四、类加载过程

  1. 加载

  2. 验证

  3. 准备

  static修饰的变量将被设置为零值。

  技术分享图片

 

   public static int value = 123; // 在准备阶段将被赋0

   public static final int value = 123; // 如果是常量,将直接初始化,而不是0,因为final的意思是:不可变的。

  4. 解析

  符号引用->直接引用

  5. 初始化

  初始化阶段才开始真正的执行JAVA代码,该阶段是虚拟机执行类构造器<clinit>()方法的过程。

  <clinit>()方法有以下特点:

  

public class Test {
    static {
        i = 0;                // 给变量赋值可以正常编译通过
        System.out.print(i);  // 这句编译器会提示“非法向前引用”
    }
    static int i = 1;
}
static class Parent {
    public static int A = 1;
    static {
        A = 2;
    }
}
 
static class Sub extends Parent {
    public static int B = A;
}
 
public static void main(String[] args) {
     System.out.println(Sub.B);  // 输出结果是父类中的静态变量 A 的值,也就是 2。
}

不为该类生成<clinit>()方法。

阻塞,所以<clinit>有耗时操作时将会造成线程阻塞。

 

原文:https://www.cnblogs.com/bloodthirsty/p/12502799.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!