Java类加载机制

一. 类加载机制三大步骤

1. 加载

  • 获得二进制流:获得.class文件的字节流,有多种方式获得.class文件,如:zip包、网络、运行时计算生成等。
  • 数据类型转换:将上一步的字节流以一定的数据结构(魔数、主次版本号、访问权限、常量池、字段表、方法表、属性表等)保存至方法区
  • 生成Class对象:在内存中生成一个代表该类的java.lang.Class对象。一般情况下,该类是在堆中的,但对于HotSpot虚拟机,则保存在方法区

2. 连接

  • 校验
    • 四大阶段
      • Class文件格式校验(魔数、主次版本号...)
      • 元数据校验(是否有父类...)
      • 字节码校验(把一个子类对象赋值给父类数据类型,这是安全的...)
      • 符号引用校验(通过全限定名是否能找到对应的类...)
    • 作用? 确保.class文件的字节流数据符合当前虚拟机的要求,并保证虚拟机的安全
  • 准备
    • 作用? 为类变量在方法区分配内存,并设置零值。
  • 解析
    • 作用? 虚拟机将方法区中常量池的符号引用替换为直接引用

3. 初始化

  • 作用? 将用户指定的值赋给类变量,以及执行静态代码块
  • 类变量赋值与静态代码块赋值顺序? 顺序执行,后面的覆盖前面的!
public class ClassLoaderSequence {

    public static int id = 1;

    static {
        age = 10;
        id  = 2;
    }

    public static int age = 20;
}

@Test
public void staticExcSequenceTest(){
    System.out.println("id  = " + ClassLoaderSequence.id);  // 2
    System.out.println("age = " + ClassLoaderSequence.age); // 20
}

二. 类加载器分类

  • 引导类加载器(Bootstrap ClassLoader)
  • 扩展类加载器(Extension ClassLoader)
  • 系统类加载器(System ClassLoader)
  • 用户类加载器(User ClassLoader)

三. 疑问

1. 什么时候触发类加载的加载阶段?

  • 运行时,用到某个类时。
    • 遇到四大字节码指令。
      • new关键字实例化对象。
      • 读取(getStatic)、设置(putStatic类字段
      • 调用类方法invokeStatic)。
    • 对类进行反射调用
      • 调用java.lang.reflect包中方法。
    • 父类尚未加载。
      • 当初始化某个类时,若发现该父类尚未初始化,则优先触发父类初始化。
  • Java虚拟机规范允许系统预加载某些类。
    • 哪些类? 系统经常用到的,如:java.util.*、java.lang.*、sun.reflect.*
    • 如何证明? 启动项目时添加-XX:+TraceClassLoading虚拟机参数。

四. 参考

  本文中,有很多细节没有展开论述,原因是因为有篇很好的文章(https://www.cnblogs.com/xrq730/p/4844915.html)已经讲得很清楚了,我也就没有必要再做赘述。

  • 《深入理解Java虚拟机》第七章    - 虚拟机类加载机制
  • 《疯狂Java讲义》          第十八章 - 类加载机制与反射(上半部分)
原文地址:https://www.cnblogs.com/YaoFrankie/p/11442934.html