大白话谈 JVM 的类加载机制,java 电子书百度云
既然我们知道了类加载的时间点,那么 jvm 是通过什么方式对类进行加载的呢?就是类加载器。
那接下来我们就来聊聊 jvm 的类加载器。
jvm 的类加载器总体上可以分成 4 层,我们一起看一下。
1.启动类加载器
首先就是 jvm 启动的第一道关口,启动类加载器 Bootstrap ClassLoader,它主要是加载 java 的核心类。
相信大家都知道,无论是什么环节下运行 java 程序,都是要安装 jvm 虚拟机环境的,而在这个环境的目录中是有一个 lib 文件夹的,这个文件下就是 java 最核心的类库,支撑着 java 系统的运行。
所以一旦 jvm 启动,那么首先就会通过启动类加载器去加载 lib 文件夹下的核心类库。
2.扩展类加载器
然后我们就到了第二层,扩展类加载器 Extension ClassLoader,这个类加载器其实与启动类加载器是类似的。
在我们的 jvm 虚拟机环境目录下,是有一个 lib/ext 的文件夹的,这里面的类就是 java 运行环境的一些扩展类,这些扩展类就是在 jvm 启动后,通过扩展类加载器进行加载的。
3.应用程序类加载器
加载完核心类库和扩展类,这时候就到了第三层,应用程序类加载器 Application ClassLoader,这个类加载器你就可以理解成是加载我们写好的 java 代码的就可以了。
4.自定义类加载器
前面的三层就是基本的类加载器了,然后第四层是自定义类加载器,根据一些特殊的需求来自己定义类加载器加载我们的类。
整体上类加载器就是这么的 4 层结构。很多小伙伴可能都听说过双亲委派机制,那么什么是双亲委派机制呢,王子就和大家用最接地气的语言描述一下。
其实很好理解,就是当我们的类加载器要加载一个类的时候,它首先会委派给它的父亲去加载,但是如果它的父亲没找到就会把这个事交给他的孩子自己去完成了。
这就是双亲委派机制。
举个例子,假如我们的应用程序类加载器要加载一个类 A,那么首先它会先回家找它老爸扩展类加载器,问问“老爸,你那有这个类 A 吗?”
然后扩展类加载器接到这个请求之后,同样也懒得处理,再去找它爷爷启动类加载器。
它爷爷找了一圈没找到类 A,很生气,就对扩展类加载器说,“我这没有,你自己找去!”
然后扩展类加载器就灰溜溜的自己找了一圈,同样也没找到,这时候就找到应用类加载器了,说:“我这哪有你这个类 A,这明明是你自己应该干的活,爱上哪找上哪找去,我不管了”。
这时候应用类加载器就只能自己去处理了,找了一圈发现找到了类 A,就把它加载到 jvm 内存中了。
相信大家看了这个例子应该很容易理解了吧。
所以假设我们自己创建了一个类 java.lang.String,它是不会被应用类加载器加载到内存中的,因为父类中可以找到这个类,就直接给加载到内存中了。
聊聊验证、准备、解析、初始化阶段
聊完了加载,我们再来看看验证、准备、解析、初始化这几个阶段 jvm 都做了什么。
1.验证阶段
这一步其实很容易理解,就是 jvm 根据 java 规范,来校验你加载进来的 class 文件中的内容是否符合规范,如果不符合规范 jvm 是无
《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
法正常运行的。
所以在加载后,首先就是验证阶段。
2.准备阶段
假设我们有一个类 A,刚刚加载并通过了验证,那么就会进行准备工作。
这个准备工作其实就是给类 A 分配一定的内存空间,然后给里面的静态变量(static 修饰的变量)也分配内存空间,并赋初始值。
3.解析阶段
这个阶段干的事实际上是把符号引用替换为直接引用,这一过程网上有很多资料,还是比较复杂的,如果感兴趣小伙伴们可以自己查阅一下资料。
实际工作中也很少会接触这部分的内容,所以我们知道有这么个阶段就可以了。
4.初始化阶段
在准备阶段,我们把类 A 的内存已经分配完了,那么初始化阶段要做些什么事呢?我们先看一下类 A 的代码
public class A {
private static String i=System.getProperty("i");
}
准备阶段我们只是给变量 i 分配了内存空间,并赋值了初始值,但是后边的 System.getProperty("i")是不会执行的。
没错,这部分代码就是在初始化阶段执行的,另外静态代码块也会在这一阶段执行。
举个例子,比如我们新建一个对象 new A(),此时就会触发从加载到初始化的全过程,把这个类准备好并创建一个实例对象。
此外这里有一个规则,如果类 A 继承了类 B,那么在初始化类 A 的时候,如果发现类 B 还没有初始化,会先初始化类 B。
扩展
到这里关于 JVM 的类加载机制其实就已经说完了,王子再给大家扩展一个小知识点。
小伙伴们想过没有,Tomcat 也是用 java 开发的,那么它的类加载机制是什么样的呢,为什么就能支持 jsp 呢?
其实它就是利用了自定义类加载器这一机制,自己自定义了很多类加载器,整体的结构如下:

Tomcat 自定义了这么多的类加载器,用来加载它自己的核心类库,并且 Tomcat 是打破了双亲委派机制的,感兴趣的小伙伴可以自己去查资料了解一下,王子就不在本篇文章长篇大论来聊 Tomcat 了。
写在最后
可能有人会问我为什么愿意去花时间帮助大家实现求职梦想,因为我一直坚信时间是可以复制的。我牺牲了自己的大概十个小时写了这片文章,换来的是成千上万的求职者节约几天甚至几周时间浪费在无用的资源上。


上面的这些(算法与数据结构)+(Java 多线程学习手册)+(计算机网络顶级教程)等学习资源
评论