一.klass模型

  1. klass模型类的继承结构
    JVM底层之类加载

  2. 普通的Java类在JVM中对应的是instanceKlass类的实例

    2.1 InstanceMirrorKlass:用于表示java.lang.Class,Java代码中获取到的Class对象,实际上就是这个C++类的实例,存储在堆区,学名镜像类
    JVM底层之类加载
    2.2 InstanceRefKlass:用于表示java/lang/ref/Reference类的子类
    JVM底层之类加载
    2.3 InstanceClassLoaderKlass:用于遍历某个加载器加载的类
    JVM底层之类加载

  3. Java中的数组不是静态数据类型,是动态数据类型,即是运行期生成的,Java数组的元信息用ArrayKlass的子类来表示:

    3.1TypeArrayKlass:用于表示基本类型的数组
    JVM底层之类加载
    3.2 ObjArrayKlass:用于表示引用类型的数组
    JVM底层之类加载

二.类加载的过程(生命周期)
JVM底层之类加载

  1. 加载

    1.1要求

    通过类的全限定名获取存储该类的class文件(没有指明必须从哪获取)
    解析成运行时数据,即instanceKlass实例,存放在方法区
    在堆区生成该类的Class对象,即instanceMirrorKlass实例

    1.2 何时加载

    1.2.1主动使用时
    1、new、getstatic、putstatic、invokestatic
    2、反射
    3、初始化一个类的子类会去加载其父类
    4、启动类(main函数所在类)
    5、当使用jdk1.7动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getstatic,REF_putstatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行初始化,则需要先出触发其初始化

Demo:
1.根据调用链可以看出,子类没有被调用,在懒加载过程中,子类是不进行初始化的,同时父类在加载过程,先加载静态代码块,然后压栈,所以最后输出结果如下JVM底层之类加载JVM底层之类加载
2.子类调用会加载父类
JVM底层之类加载
JVM底层之类加载
3.final修饰静态常量,类不用加载
JVM底层之类加载
JVM底层之类加载
4.final 修饰的静态变量,类是需要加载的
JVM底层之类加载
JVM底层之类加载
5.反射调用过程中当前类会加载
JVM底层之类加载JVM底层之类加载
1.2.2 预加载
包装类、String、Thread

  1. 验证
    1、文件格式验证
    2、元数据验证
    3、字节码验证
    4、符号引用验证

  2. 准备
    为静态变量分配内存、赋初值
    实例变量是在创建对象的时候完成赋值的,没有赋初值一说
    JVM底层之类加载
    如果被final修饰,在编译的时候会给属性添加ConstantValue属性,准备阶段直接完成赋值,即没有赋初值这一步
    JVM底层之类加载

  3. 解析
    将常量池中的符号引用转为直接引用
    解析后的信息存储在ConstantPoolCache类实例中
    1、类或接口的解析
    2、字段解析
    3、方法解析
    4、接口方法解析

何时解析
思路:
1、加载阶段解析常量池时
2、用的时候
openjdk是第二种思路,在执行特定的字节码指令之前进行解析:
anewarray、checkcast、getfield、getstatic、instanceof、invokedynamic、invokeinterface、invokespecial、invokestatic、invokevirtual、ldc、ldc_w、ldc2_w、multianewarray、new、putfield

  1. 初始化
    执行静态代码块,完成静态变量的赋值
    静态字段、静态代码段,字节码层面会生成clinit方法
    方法中语句的先后顺序与代码的编写顺序相关

相关文章: