虚拟机类加载机制

一、类的生命周期

加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载

有且仅有以下情况,JVM必须立即对类进行初始化:

  1. new、getstatic、putstatic、invokestatic
  2. 使用反射对类进行调用时
  3. 初始化一个类,发现其父类还未进行初始化,则先初始化父类
    (接口初始化,并不要求其父接口初始化,只有在真正使用到父接口(如引用接口中定义的常量)才会初始化;
    调用类中的常量,不会触发初始化)
  4. JVM启动时,会先初始化main方法所在类

注意以下几点,不会触发类的初始化

  1. 通过数组引用类,不会触发初始化,如:
    SomeClass[] someClassArr = new SomeClass[10];
  2. 常量在编译阶段会存入调用类的常量池,本质上并没有直接引用到定义类,如:
    System.out.println(Constants.HELLO);
二、类的加载过程
  1. 加载
    • 通过类的全限定名,获取类的二进制字节流
    • 将字节流代表的静态存储结构转化为方法区的运行时数据结构
    • 方法区(针对HotSpot而言)生成一个代表此类的java.lang.Class对象。
      这个对象将作为程序访问方法区中这些类型数据的外部接口
  2. 验证
    其中,符号引用验证,发生在JVM将符号引用转化为直接引用的时候(解析阶段)。
  3. 准备
    类变量(被static修饰的变量)分配内存并设置初始值,这些变量所使用的内存,在方法区分配
    特殊情况:如果是常量,则在准备阶段直接赋给定值
  4. 解析
    JVM将常量池内的符号引用替换为直接引用的过程,包括以下常量:
  • CONSTANT_Class_info
  • CONSTANT_Methodref_info
  • CONSTANT_Fieldref_info
  • CONSTANT_InterfaceMethodref_info
  1. 初始化
    执行的过程,c指class的意思。
    JVM会保证只执行一次,即便在多线程环境中
    是编译器自动收集类中所有static变量的赋值动作和static{}, 并按源文件中出现顺序形成的
三、类加载器

每一个类加载器,都拥有一个独立的类命名空间,【命名空间 + 类全限定名】唯一确定一个类。

双亲委派模型
父加载器反馈无法加载时,才由子加载器自己加载

  1. 避免重复加载
  2. 防止JVM类(如Object.class被覆盖)
  • Bootstrap ClassLoader
    /lib下,并且仅按照文件名识别(如rt.jar)
  • 扩展类加载器
    /lib/ext下
  • 应用程序类加载器
    classpath指定路径

你可能感兴趣的:(虚拟机类加载机制)