来聊聊JVM中的类加载过程以及双亲委派模型(学习Java必知内容)

文章目录


1. 类加载过程

在整个 JVM 执行过程中, 和我们程序员关系最密切的就是类加载的过程, 所以接下来我们来看下类加载的执行流程.

对于一个类来说, 它的生命周期是这样的:

其中前 5 步是固定的顺序并且也是类加载的过程, 其中中间的 3 步我们都属于连接, 所以对于类加载来说总共分为以下几个步骤:

  1. 加载
  2. 验证
  3. 准备
  4. 解析
  5. 初始化

类加载, 是一个非常复杂的过程, 此处我们只是简单介绍一下类加载的大致流程. 细致解析需到 Java 官方文档进行查阅. 下面我们来看看每个步骤的具体执行内容.

加载

"加载"(Loading)阶段指的是整个"类加载"(Class Loading)过程中的一个阶段,在加载 Loading 阶段,Java虚拟机需要完成以下三件事情:

  1. 通过一个类的全限定名来获取定义此类的二进制字节流。
  2. 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  3. 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

通俗来说, 就是找到 .class 文件, 打开文件, 读取文件内容, 并尝试解析里面的格式.

验证

验证这一阶段的目的是, 确保 .class 文件的字节流中包含的信息符合《Java虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。

验证选项:

  • 文件格式验证
  • 字节码验证
  • 符号引用验证
  • ...

准备

准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段。最终的目标是构造出完整的类对象。

比如此时有这样一行代码:

public static int value = 123;

它在这个阶段 value 的 int 值是赋为 0,而非 123。

解析

解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程。

主要是初始化类中涉及到的一些字符串常量。

初始化

初始化阶段,Java 虚拟机真正开始执行类中编写的 Java 程序代码,将主导权移交给应用程序。初始化阶段就是执行类构造器方法的过程。

也就是这个环节,开始对类对象进行更具体的初始化操作。比如初始化静态成员,执行静态代码块,加载父类等等。

2. 双亲委派模型

谈到类加载机制, 不得不提的一个概念就是 "双亲委派模型".

双亲委派模型, 可以理解为就是类加载中 JVM 如何去找 .class 文件的一个过程.

JVM 加载 .class 文件时, 会使用到 "类加载器" 模块, JVM 中自带了三个类加载器.

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无 法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。

一个类的加载流程

  1. 首先, 会从 Application ClassLoader 开始. 但不会立即就搜索第三方库的目录, 而是先把加载任务委派给父类, 让父类先尝试加载.
  2. 到了 Extension ClassLoader, 也不会立即就搜索扩展库的目录, 也会把加载任务委派给父类, 也让父类尝试加载.
  3. 到了 Bootstrap ClassLoader, 也想着把任务委派出去, 可是 Bootstrap ClassLoader 已经没有父类了, 只能自己动手搜索类了. 如果找到了这个类, 就会进行后续的加载. 如果没找到这个类, 就会将这个任务交回给子类加载器去完成.
  4. 任务回到了 Extension ClassLoader, 此时收到父类交回的任务后, 就会开始搜索扩展库的目录, 看看有没有匹配的 .class 文件. 如果找到了这个类, 就会进行后续的加载. 如果没找到这个类, 就会将这个任务交回给子类加载器去完成.
  5. 任务回到 Application ClassLoader, 此时就会开始搜索第三方库的目录(往往是自己开发时的项目目录), 如果找到了这个类, 就会进行后续的加载. 如果没找到这个类, 这时就会抛出异常.

双亲委派模型的优点

  1. 避免重复加载类:比如 A 类和 B 类都有一个父类 C 类,那么当 A 启动时就会将 C 类加载起来,那么在 B 类进行加载时就不需要在重复加载 C 类了。
  2. 安全性 :使用双亲委派模型也可以保证了 Java 的核心 API 不被篡改,如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类,而有些 Object 类又是用户自己提供的因此安全性就不能得到保证了。

总结

✨ 本文主要讲解了 JVM 中的类加载过程, 以及其中涉及到的双亲委派模型, 是我们学习 Java 过程中, 需要着重了解的.

✨ 想了解更多知识, 请持续关注博主, 本人会不断更新学习记录, 跟随我一起不断学习.

✨ 感谢你们的耐心阅读, 博主本人也是一名学生, 也还有需要很多学习的东西. 写这篇文章是以本人所学内容为基础, 日后也会不断更新自己的学习记录, 我们一起努力进步, 变得优秀, 小小菜鸟, 也能有大大梦想, 关注我, 一起学习.

再次感谢你们的阅读, 你们的鼓励是我创作的最大动力!!!!!

相关推荐
Swift社区11 分钟前
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
开发语言·ios·swift
没头脑的ht12 分钟前
Swift内存访问冲突
开发语言·ios·swift
没头脑的ht15 分钟前
Swift闭包的本质
开发语言·ios·swift
wjs202418 分钟前
Swift 数组
开发语言
吾日三省吾码1 小时前
JVM 性能调优
java
stm 学习ing1 小时前
FPGA 第十讲 避免latch的产生
c语言·开发语言·单片机·嵌入式硬件·fpga开发·fpga
湫ccc2 小时前
《Python基础》之字符串格式化输出
开发语言·python
弗拉唐2 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
Red Red2 小时前
网安基础知识|IDS入侵检测系统|IPS入侵防御系统|堡垒机|VPN|EDR|CC防御|云安全-VDC/VPC|安全服务
网络·笔记·学习·安全·web安全