JVM类加载

105 阅读3分钟

类加载

加载对象

  1. java类型分为基本类型和引用类型,基本类型是有jvm定义好的,引用类型分为四种,类接口数组类,泛型,泛型会在编译过程中被擦除,因此实际只有三种,数组类是由java虚拟机直接生成的,其他两种则有对应字节流
  2. 字节流最常见的就是java编译生成的class文件,除此之外,也可以在程序内部生成或者从网络中获取,这些字节流都会被加载到java虚拟机中

步骤

  1. 加载:加载就是查找字节流并据此创建类的过程,
    1. 对于数组类来说,没有对应字节流,由java虚拟机生成,对于其他类来说,则需要借助类加载器来完成。
    2. bootstrapClassLoader由cpp实现,没有对应java对象,其他的类加载器都是CLassLoader的子类,因此有对应的java对象,这些加载器需要先由其他加载器如boosrtap加载到jvm后才能执行类加载
    3. 类加载中有一个双亲委派模型,每当一个类加载器接收到加载请求,会先将请求转发给父类加载器,父类加载器没找到所请求的类的情况下,该类才会尝试加载
    4. boostrap负责加载最重要最基础的类,如jre/lib目录下的类,除此之外,还有extension负责加载相对次要的类如jre/lib/ext目录下的类,application负责加载应用程序路径下的类 classpath;同时,我们还可以加入自定义类加载器来实现特殊的加载方式
    5. 并且,类加载器还提供了命名空间的作用,类的唯一性由类加载器实力以及类名一起确定,我们可以通过这一特性,来运行一个类的不同版本
  2. 链接:链接就是将创建的类合并到jvm,使之能够执行的过程,分为验证,准备,解析三个过程
    1. 验证目的在于确保被加载类能够满足jvm约束条件
    2. 准备目的在于为被加载类静态字段分配内存
    3. 解析目的是将符号引用解析为实际应用,如果符号引用执行未加载的类,那么解析将触发这个类的加载,但未必会触发链接和初始化
  3. 初始化:
    1. java中如果要初始化一个静态字段,可以在声明时直接赋值,也可以在静态代码块中赋值
    2. 如果直接赋值的静态字段被final修饰并且是基本类型或字符串,那么会被java编译器标记为常量,其初始化直接由jvm完成
    3. 除此之外的直接赋值以及所有静态代码块的代码,则会被java编译器置于clinit方法中
    4. 类加载的最后一步是初始化,即为常量字段赋值以及执行clinit方法,jvm通过加锁来保证clinit方法只执行一次
    5. 类初始化触发时机:
      1. jvm启动时,初始化用户指定的主类
      2. 遇到new指令时,初始化new目标类
      3. 调用静态方法或者访问静态字段时,初始化静态方法所在的类
      4. 子类初始化会触发父类初始化