本文主要是介绍Java类加载器,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
前言
未完待更(实例,部分源码解析,自定义类加载器编写,打破双亲委派机制)
本文章中使用的环境及版本:
- 开发工具:Intellij IDEA 2017.3.4
- jdk:1.8.0_171
目录
- 前言
-
- 1. 类的加载过程
- 2. 类加载器
- 3. 双亲委派机制
1. 类的加载过程
首先看一张类加载以及前后过程的流程图
![在这里插入图片描述](/upload/202108/05/202108050106423102.png)
流程图中可以看到一个类的生命周期分为:加载→验证→准备→解析→初始化→使用→卸载七个阶段,其中标绿的五个阶段为一个类的完整加载过程,这五个步骤统称为类的加载,以下着重对这五个步骤进行简单介绍
- 加载:通过类的全名在硬盘上搜索并获取其二进制字节流,并将其读入JVM方法区,同时在堆内存中创建该类的Class对象。
- 验证:通过文件格式验证、元数据验证、字节码验证和符号引用验证四个验证来确保被加载类的正确性,保证.class文件中的二进制字节流符合JVM要求且不会危害JVM。
- 准备:仅为类中的静态变量(被static修饰的变量)分配内存并初始化为默认值,不会为普通成员变量分配内存,其中用被final static修饰的变量在编译阶段就已经完成分配。
- 解析:将常量池中的符号引用转换为直接引用。
- 初始化:若有该类有父类未被初始化,则先初始化其父类,随后为类的静态变量赋初始设定值,执行静态代码块。
2. 类加载器
类加载器负责将.class文件加载到JVM内存中,并生成与之相对应的Class对象。
类加载器一共分为三种:启动类加载器、扩展类加载器、应用类加载器。
- 启动类加载器(BootstrapClassLoader):也叫引导类加载器,本加载器由C++实现,负责加载jre/lib目录下的核心类库,比如rt.jar、charsets.jar等。
注:JAVA的沙箱安全机制严格限制代码对本地资源的访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏。沙箱安全机制体现在启动类加载器上就是该启动类只会加载指定包(java、sun等包)下的类,且会优先加载JDK自带的类,同包同名外部类也不会被加载,保护了JAVA核心源代码。 - 扩展类加载器(ExtClassLoader):负责加载jre/lib/ext目录中的JAR类包(通常为非原生被引用的jar包)。
- 应用类加载器(AppClassLoader):也叫系统类加载器,负责加载用户自定义路径下的class字节码文件,通常该加载器为程序默认加载器。
除了以上三种类加载器,我们还可以自定义类加载器,根据需求扩展类的加载方式,后文中会进行演示。
3. 双亲委派机制
双亲委派机制如下图所示、
![在这里插入图片描述](/upload/202108/05/202108050106424040.png)
可以简单吧双亲委托机制看成两个部分:委托和加载(非官方,作者个人理解)
- 委托:当收到类加载请求时,最先调用应用类加载器(前文中有提及,通常应用类加载器为程序中的默认加载器),判断此前应用类加载器是否加载过该类,若没有加载过,则向上委托给其父类扩展类加载器,扩展类加载器执行同样的操作,若扩展类加载器也没有加载过,则向上委托给其父类启动类加载器,同样先执行判断操作。在以上三次判断操作中,若发现曾加载过此类,则直接返回,不再向上进行委托;若直到启动类加载器也没有加载过该类,则进行加载操作。
- 加载:加载操作由启动类加载器先开始,启动类先搜索jre/lib目录下的核心类库中是否有该类,若有,加载后返回,若没有,则由其子类继续执行加载操作,扩展类加载器和应用类加载器同理。
注:启动类加载器、扩展类加载器以及应用类加载器之间并无继承关系,提及父类子类是因为在ClassLoader类中存在一共parent变量,后文中会提及。
使用双亲委派机制的优点:
- 先判断再加载的机制避免了类的重复加载问题
- 加载时,加载顺序为启动类加载器→扩展类加载器→应用类加载器,实质上是从核心类库到自定义类的加载顺序,这样的顺序解决了一些安全问题,比如用户自定义了一个String类,这与java.lang包下的String类同名,使用双亲委派机制就会优先加载JDK自带的String类而忽视用户自定义的String类,防止JAVA核心代码被篡改
未完待更!
作者才疏学浅,如文中出现纰漏,还望指正
这篇关于Java类加载器的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!