urlname
type
Post
password
SyncToConfluence
category
学习笔记
date
Apr 13, 2024
slug
01HV9NP1YQAFWF4JEEY83CHV72
icon
Button
catalog
summary
tags
JVM
Java
cover
Status
BusyTime
Status 1
status
Published
😀
Java类的加载过程是Java虚拟机(JVM)进行类处理的一个核心部分,涉及到将类的.class文件从磁盘加载到内存,并为之准备运行环境的一系列步骤。 Java类的加载、链接和初始化过程严格规定了各个步骤的执行顺序,确保Java程序能正确运行。

Java类加载过程

加载-Loading

  • 职责
    • 将.class文件,加载进JVM,并创建Class对象。
  • 作用:
    • 将类的.class文件中的原始字节流转换为方法区中的运行时数据结构。
    • 在Java堆中创建一个Class对象,作为方法区这些数据的访问入口。
  • 关键组件:
    • 类加载器
  • 涉及内容:
    • 类加载器(如Bootstrap ClassLoader、Extension ClassLoader、Application ClassLoader及用户自定义类加载器)。
    • Class文件格式。
    • 二进制字节流到JVM内部结构的映射。

链接-Linking

  • 职责:
    • 验证类的正确性,为类变量分配内存,并解析该类创建的符号引用到具体的内存地址中。
  • 作用:
    • 确保类在JVM中正确、安全地布局。
    • 将内存中的符号引用替换为可以直接由JVM使用的地址或指针。
  • 三个阶段:
    • 验证(Verification):验证加载的类是否符合JVM规范。
    • 准备(Preparation):为类变量分配内存,并设置默认初始化值。
    • 解析(Resolution):将符号引用转化为直接引用。
  • 涉及内容:
    • 类和接口的解析。
    • Java虚拟机规范中的数据类型和结构。
    • 内存管理和符号表。

初始化-Initialization

  • 职责:
    • 执行静态初始化器和静态初始化块。
    • 对类进行初始化,执行类构造器方法。
  • 作用:
    • 初始化类变量。
  • 涉及内容:
    • Java内存模型(JMM)。
    • 类的生命周期。

相关问题

为什么需要不同的类加载器

  • 隔离:不同的类加载器可以用于加载不同来源的代码,从而保证了运行时环境的安全性和类之间的隔离,防止类的名称冲突。
  • 安全性:系统类和应用类使用不同的加载器,可以防止恶意代码替换核心的API类,增强JVM的安全性。
  • 灵活性:允许从各种来源动态加载类,如从网络、动态生成的代码或其他文件格式。

不同类加载器之间的关系

类加载器有一个父子层级关系,类似一个树形结构。类加载器可以被分为以下几种:
  • 启动类加载器(Bootstrap ClassLoader)
    • 虚拟机的内置类加载器,负责加载Java的核心库(如rt.jarresources.jar等JRE的核心类库)。
    • 启动类加载器是用原生代码实现的,并不继承自java.lang.ClassLoader
  • 扩展类加载器(Extension ClassLoader)
    • 从JDK的扩展目录(jre/lib/ext或者由系统属性java.ext.dirs指定的任何目录)加载类库。
    • java.lang.ClassLoader的子类,其父加载器是启动类加载器。
  • 应用程序类加载器(Application ClassLoader)
    • 类加载器架构中的默认类加载器,用于加载来自应用程序类路径(Classpath,环境变量中设置的)的类。
    • 父加载器是扩展类加载器。
  • 用户自定义加载器
    • 继承自java.lang.ClassLoader的加载器,用于特定的加载需求,如从网络或加密存储中加载类。

类加载器的加载原则

  • 双亲委托机制
    • 当一个类加载器收到类加载的请求时,它首先不会自己尝试去加载这个类,而是把这个请求委派给父类加载器去完成。
    • 只有当父加载器无法完成这个请求时(它不认识这个类),子加载器才会尝试自己去加载。
  • 可见性
    • 子加载器可以访问父加载器加载的类,而父加载器则不能访问子加载器加载的类。
  • 单一性
    • 由同一个类加载器加载的类在JVM中只有一个唯一实例
    • 这也是JVM保证加载的类在JVM内部的唯一性的方式。

没有被实例化的类,会被类加载器加载吗?

不一定,类的加载通常是因为要首次使用该类,而“使用”可以有多种形式,不限于实例化。
以下是触发类加载的几种常见情况:
  • 创建实例
  • 访问静态成员:访问类的静态字段或调用类的静态方法也会触发类的加载。
  • 反射:使用反射API如 Class.forName("com.example.MyClass") 来动态加载类,无论是否创建实例。
  • 继承:当一个类被另一个类继承,父类将被加载(如果尚未加载)。即使子类没有被实例化,父类也需要加载以解析类的结构。
  • 使用类或接口:直接使用类或接口来定义引用变量。
 
Android IPC笔记整理Leetcode 2924. 找到冠军 II
Loading...