文章目录
- 1. 类加载器简介
- 2. 类加载器的种类
- 3. 类加载执行过程
- 3.1 加载
- 3.2 验证
- 3.3 准备
- 3.4 解析
- 3.5 初始化
- 3.6 使用
- 3.7 卸载
1. 类加载器简介
类加载器(Class Loader)是 Java 虚拟机(JVM)的一部分,JVM只会运行二进制文件,而类加载器(ClassLoader)的主要作用就是从文件系统、网络等地方加载Java类文件到内存,并在运行时动态链接和验证这些类。类加载器负责加载Java字节码文件,并将其转换为可执行的Java类或接口。类加载器通常按照层次结构组织,除了顶层的类加载器外,每个类加载器都有一个父类加载器。当类加载器需要加载一个类时,它会先尝试自己加载,如果无法找到,则会委托给父类加载器,直到顶层的类加载器尝试加载。如果所有的父类加载器都无法加载,则会抛出ClassNotFoundException 异常。
一个Java文件,它从编译到执行的整个过程。
- 类加载器:用于装载字节码文件(.class文件)
- 运行时数据区:用于分配存储空间
- 执行引擎:执行字节码文件或本地方法
- 垃圾回收器:用于对JVM中的垃圾内容进行回收
2. 类加载器的种类
- 启动类加载器(Bootstrap ClassLoader):它是JVM的一部分,负责加载Java的核心类库,如java.lang包中的类。它是JVM自身的一部分,由C++实现,不是Java类,因此在Java中无法直接获取到启动类加载器的引用。
- 扩展类加载器(Extension ClassLoader):它负责加载Java的扩展类库,位于JRE的lib/ext目录下的jar包。开发者可以通过系统属性java.ext.dirs指定扩展类库的路径。
- 应用程序类加载器(Application ClassLoader):也称为系统类加载器,它负责加载应用程序的类,即开发者自己编写的类。它是ClassLoader类的子类,是Java中默认的类加载器。
- 自定义类加载器:开发者可以通过继承ClassLoader类,实现自己的类加载器。自定义类加载器可以加载特定路径下的类文件,或者从其他来源(如网络、数据库)加载类。
上述三种类加载器的层次结构如下如下:
类加载器采用双亲委派模型(Parent Delegation Model)来加载类。即当一个类加载器收到加载类的请求时,它会首先将这个请求委派给父加载器来尝试加载,只有当父加载器无法加载时,才会由当前加载器自己来加载。
这种层次结构的类加载器可以保证Java类的安全性和一致性。通过双亲委派模型,可以确保核心类库的安全性,避免了不同类加载器加载同一个类的问题。同时,开发者也可以通过自定义类加载器来实现特定的加载逻辑,例如加载加密的类文件、加载网络上的类等。
3. 类加载执行过程
类从加载到虚拟机中开始,直到卸载为止,它的整个生命周期包括了:加载、验证、准备、解析、初始化、使用和卸载这7个阶段。其中,验证、准备和解析这三个部分统称为连接(linking)。
3.1 加载
- 通过类的全名,获取类的二进制数据流。
- 解析类的二进制数据流为方法区内的数据结构(Java类模型)
- 创建java.lang.Class类的实例,表示该类型。作为方法区这个类的各种数据的
访问入口
3.2 验证
验证类是否符合JVM规范,安全性检查
- 文件格式验证:是否符合Class文件的规范
- 元数据验证
- 这个类是否有父类(除了Object这个类之外,其余的类都应该有父类)
- 这个类是否继承(extends)了被final修饰过的类(被final修饰过的类表示类不能被继承)
- 类中的字段、方法是否与父类产生矛盾。(被final修饰过的方法或字段是不能覆盖的)
- 字节码验证:主要的目的是通过对数据流和控制流的分析,确定程序语义是合法的、符合逻辑的。
- 符号引用验证:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量
int i = 3;
字面量:3
符号引用:i
3.3 准备
为类变量分配内存并设置类变量初始值
- static变量,分配空间在准备阶段完成(设置默认值),赋值在初始化阶段完成
- static变量是final的基本类型,以及字符串常量,值已确定,赋值在准备阶段完成
- static变量是final的引用类型,那么赋值也会在初始化阶段完成
3.4 解析
把类中的符号引用转换为直接引用
比如:方法中调用了其他方法,方法名可以理解为符号引用,而直接引用就是使用指针直接指向方法。
3.5 初始化
对类的静态变量,静态代码块执行初始化操作
- 如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。
- 如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。
3.6 使用
JVM 开始从入口方法开始执行用户的程序代码
- 调用静态类成员信息(比如:静态字段、静态方法)
- 使用new关键字为其创建对象实例
3.7 卸载
当用户程序代码执行完毕后,JVM 便开始销毁创建的 Class 对象,最后负责运行的 JVM 也退出内存.