JVM类加载

目录

  • 前言
  • [1. 类加载过程](#1. 类加载过程)
    • [1.1 加载](#1.1 加载)
    • [1.2 验证](#1.2 验证)
    • [1.3 准备](#1.3 准备)
    • [1.4 解析](#1.4 解析)
    • [1.5 初始化](#1.5 初始化)
  • [2. 双亲委派模型](#2. 双亲委派模型)
  • 总结

前言

JVM的意思是Java虚拟机,是Java运行的基础,其中执行流程中有个过程叫做类加载,本篇文章就来介绍类加载。

1. 类加载过程

类加载分为以下几个步骤:加载、连接(验证、准备、解析)、初始化。下面将以加载、验证、准备、解析、初始化这五个步骤进行讲述。

1.1 加载

首先根据代码中编写的"全限定类名"(包名+类名,例如java.lang.String),找到".class"文件,找的过程称为"双亲委派模型,在下面会讲述";然后打开文件,读取文件到内存中;最后进行数据格式的解析。

1.2 验证

校验上述的.class"中读取的内容,是否合法。假设你拿一个图片的二进制文件,后缀改为".class",此时读取的内容就是不合法的。在验证过程中,如果发现某个地方的格式存在问题,就需要及时报错。

1.3 准备

给类对象分配内存空间。类加载最终得到的结果则是内存中的"类对象"。这里分配的空间,是一个未初始化的内存空间,具体来说,空间上的每个字节都是"0"。

1.4 解析

针对代码中的常量进行初始化。在".class"文件中,也会涉及到一些常量,这也是需要放到内存中的,所以也需要对常量进行初始化,方便加载到内存中。

1.5 初始化

开始执行类中编写的Java程序代码。类的静态成员执行真正的初始化操作,静态代码块执行,同时还有父类/需要实现的接口的加载。

2. 双亲委派模型

JVM中进行类加载的操作,需要依赖内部的模块,叫做类加载器(class loader),在进行类加载时,首先需要找到对应的类。JVM自带了三种类加载器:Bootstrap ClassLoader(负责在Java标准库中查找)、ExtensionClassLoader(负责在Java的扩展库中查找)、ApplicationClassLoader(负责在Java第三方库/当前项目进行查找)。

在这三个类加载器之间,存在"父子关系",都有一个parent这样的属性,保存了自己的父亲是谁(BootstrapClassLoader>ExtensionClassLoader>ApplicationClassLoader。

假设要加载一个类java.lang.String,调用的入口是ApplicationClassLoader,拿到任务后,先把任务抛给父亲,最后会抛给ApplicationClassLoader,搜索自己负责的目录(标准库目录),发现能找到,就继续后续的加载流程。

如果ApplicationClassLoader没有找到,就将任务抛回ExtensionClassLoader,如果还没有找到,继续抛回BootstrapClassLoader,如果还没有找到,就会抛出异常ClassNotFoundException。

双亲委派模型也是可以打破的,在特定场景下,程序员可以实现自己的类加载器,这种自己实现的类加载器可以自行判断是否要遵守双亲委派模型。

总结

本篇文章介绍了JVM类加载的基本流程,同时介绍了加载阶段的双亲委派模型。希望大家看完之后能对类加载的过程有所了解。