【JVM】类加载过程|双亲委派模型

 思维导图目录

四、类加载过程

1.类加载过程

2.双亲委派模型(经典面试题)

什么是双亲委派模型

双亲委派模型的优点

 破坏双亲委派模型


四、类加载过程

1.类加载过程

咱们写的java代码,是.java文件(硬盘),一个java进程要跑起来,就需要把.java先变成.class文件(硬盘),加载到内存中,得到“类对象”,其中就执行了指令,要执行的CPU指令,都是通过字节码(进入内存中)让JVM翻译出来的

从上⾯的图⽚我们可以看出整个JVM执⾏的流程中,和程序员关系最密切的就是类加载的过程了,所以接下来我们来看下类加载的执⾏流程。

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

类加载的几个环节(八股)

1.加载:在硬盘上,找到对应的.class文件,读取文件内容

2.验证:检查.class里的内容,是否符合要求

3.准备:给类对象,分配内存空间(元数据区)(类加载最终要得到的就是类对象),会把这个空间里的数据先全都填充为0(此时,如果这个类有静态成员,值就是0)

4.解析:针对字符串常量来初始化,把刚才.class文件中的常量的内容取出来,放到“元数据区”

5.初始化:针对类对象进行初始化(不是针对对象初始化,和构造方法无关),给静态成员进行初始化,执行静态代码块

此时类对象就搞定了

后续代码就可以使用这个类对象,创建实例,或者使用里面的静态成员了


2.双亲委派模型(经典面试题)

提到类加载机制,不得不提的⼀个概念就是“双亲委派模型”

站在Java虚拟机的⻆度来看,只存在两种不同的类加载器:⼀种是启动类加载器(Bootstrap  ClassLoader),这个类加载器使⽤C++语⾔实现,是虚拟机⾃⾝的⼀部分;另外⼀种就是其他所有的类加载器,这些类加载器都由Java语⾔实现,独⽴存在于虚拟机外部,并且全都继承⾃抽象类java.lang.ClassLoader。

站在Java开发⼈员的⻆度来看,类加载器就应当划分得更细致⼀些。⾃JDK 1.2以来,Java⼀直保持着三层类加载器、双亲委派的类加载架构器


什么是双亲委派模型

它出现在“加载”环节(第一步),根据代码中的写的“全限定类名”(包名+类名)找到对应的.class文件

这个模型描述了JVM加载.class文件过程中,找文件的过程

“类加载模型”在JVM中包含的一个特定的模块/类,这个类负责完成后续的类加载工作

JVM中内置了三个类加载器,负责加载不同的类

1)BootstrapClaaLoader (相当于爷爷)

负责加载标准库的类

2)ExtentionClassLoader(相当于父亲)

负责加载JVM扩展库的类

3)ApplicationClassLoader(相当于儿子)

负责加载第三方库的类自己写的代码的类

 此处的“父子关系”不是通过类的继承表示的(不是父类子类),而是通过类加载器中存在一个“parent”这样的字段,指向自己的父亲,类似于二叉树中的“三叉实现形式”)

“双亲委派模型”本身翻译是不准确的,更准确的翻译:“父亲委派模型”,“单亲委派模型”

工作过程举例:

给定一个类的全限定类名:java111.Test

此时加载过程如下:

(1)工作从ApplicationClassLoader开始进行

ApplicationClassLoader并不会立即搜索第三方库的相关目录,而是把任务交给自己的父亲来进行处理

(2)工作就到ExtentionClassLoader

ExtentionClassLoader也不会立即搜索负责的扩展库的目录,也是把任务交给自己的父亲来处理

(3)工作就来到BootstrapClaaLoader

BootstrapClaaLoader也像交给自己的父亲来处理,但是它的parent指向null,只能自己处理,BootstrapClaaLoader尝试在标准库的路径中搜索上述的类

(4)工作回到了ExtentionClassLoader

此时就要搜索扩展库对应的目录了

如果找到了,就由当前的类加载器负责打开文件,读取文件等后续操作...

如果找不到,任务就还是要继续还给儿子来处理

(5)工作回到了ApplicationClassLoader

此时要搜索第三方库/用户项目代码的目录了

如果找到了,也就是由当前的类加载器负责处理

如果没有找到,任务还是要继续还给儿子来处理

but,此时没有儿子了,还没找到,最早就会抛出一个ClassNotFoundException

本质就是:拿到任务,先交给父亲处理,父亲处理不了,在自己处理


双亲委派模型的优点

1. 避免重复加载类:⽐如A类和B类都有⼀个⽗类C类,那么当A启动时就会将C类加载起来,那么在B类进⾏加载时就不需要在重复加载C类了。

2. 安全性:使⽤双亲委派模型也可以保证了Java的核⼼API不被篡改,如果没有使⽤双亲委派模型,⽽是每个类加载器加载⾃⼰的话就会出现⼀些问题,⽐如我们编写⼀个称为java.lang.Object类的话,那么程序运⾏的时候,系统就会出现多个不同的Object类,⽽有些Object类⼜是⽤⼾⾃⼰提供的因此安全性就不能得到保证了(JVM会确保加载的类是标准库的类)


 破坏双亲委派模型

but 双亲委派模型虽然有其优点,但在某些情况下也存在⼀定的问题,⽐如Java中SPI(Service Provider Interface,服务提供接⼝)机制中的JDBC实现:

因为DriverManager位于rt.jar包,由BootStrap类加载器加载,⽽其Driver接⼝的实现类是位于服务商提供的Jar包中,是由⼦类加载器(线程上下⽂加载器 Thread.currentThread().getContextClassLoader)来加载的,这样就破坏了双亲委派模型了(双亲委派模型讲的是所有类都应该交给⽗类来加载,但JDBC显然并不能这样实现)

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深鱼~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值