Android---深入理解ClassLoader的加载机制

news2025/1/10 2:56:08

目录

Java 中的 ClassLoader

1. APPClassLoader 系统类加载器

2. ExtClassLoader 扩展类加载器

3. BootstrapClassLoader 启动类加载器

双亲委派模式(Parents Delegation Model)

Android 中的 ClassLoader

1. PathClassLoader

2. DexClassLoader

总结


一个完整的 Java 程序是由多个 .class 文件组成的,在程序运行的过程中,需要将这些 .class 文件加载到 JVM 中才可以使用,而负责加载这些 .class 文件的就是类加载器(ClassLoader)

Java 中的类何时被类加载器加载

Java 程序启动时,并不会一次性加载程序中所有的 .class 文件,而是在程序运行过程中,动态的加载相应的类到内存中。通常情况下,Java 程序中的 .class 文件会在以下两种情况下被 Class Loader 主动加载到内存:

1. 调用类构造器;

2. 调用类中的静态变量或者静态方法。

Java 中的 ClassLoader

JVM 中自带3个类加载器:

\bullet 启动类加载器 BootstrapClassLoader;

\bullet 扩展类加载器 ExtClassLoader(JDK1.9 之后,改名为 PlatformClassLoader);

\bullet 系统类加载器 APPClassLoader。

1. APPClassLoader 系统类加载器

部分源码如下

可以看出 APPClassLoader 主要加载系统属性“java.class.path”配置下类文件,也就是环境变量 classpath 配置的路径下的文件。因此,APPClassLoader 是面向用户的类加载器。我们自己编写的代码以及使用的第三方 jar 包,通常都是由它来加载的。

2. ExtClassLoader 扩展类加载器

部分源码如下:

可以看出,扩展类加载器(ExtClassLoader )主要加载系统属性“java.ext.dirs”配置下类文件,可以通过如下代码打印出这个属性来查看具体有哪些文件。

System.out.println(System.getProperty("java.ext.dirs"));

3. BootstrapClassLoader 启动类加载器

BootstrapClassLoader 是由 C/C++ 语言编写的,它本身属于虚拟机的一部分,因此无法在 java 代码中直接获取它的引用。如果尝试在 Java 层获取 BootstrapClassLoader 的引用,系统会返回 null。

启动类加载器加载“sun.boot.class.path”配置下类文件,可以打印这个属性来查看具体有哪些文件

System.out.println(System.getProperty("sun.boot.class.path"));

结果如下:

可以看出这些全身 jre 目录下的的 jar 包或者 classes 文件。

双亲委派模式(Parents Delegation Model)

既然 JVM 中已经有了这3种 ClassLoader,那么 JVM 又是如何知道该使用哪一个类加载器去加载相应的类呢?答案这是:双亲委派模式。

双亲委派模式:当类加载器受到加载类或资源的请求时,通常都是先委托给父类加载器加载,只有当父类加载器找不到指定的类或资源时,自身才会执行实际的类加载过程。

其具体实现代码是在CLassLoader.java 中的 loadClass 方法中,如上图所示:

解释说明:上图中1处判断该 class 是否已经加载。如果已经加载,直接将该 class 返回;2处,如果该 class 没有被加载过,则判断 parent 是否为空,如果不为空则将加载的任务委托给 parent;3处,如果 parent 为空,则直接调用 BootstrapClass Loader 加载该类;4处,如果 parent 和 BootstrapClassLoader 都没有加载成功,则调用当前 ClassLoader 的 findClass() 方法继续尝试加载。

那么这个 parent 是什么呢?我们可以看 ClassLoader 的构造器,如下:

可以看出,在每一额 ClassLoader 中都有一个 ClassLoader 类型的 parent 引用,并且在构造器中传入值。继续查看源码,可以看到 AppClassLoader 传入的 parent 就是 ExtClassLoadr,而 ExtClassLoadr并没有传入任何 parent,也就是 null。

举例说明:

Test test = new Test();

默认情况下,JVM 首先调用 AppClassLoader 去加载 Test 类

1. APPClassLoader 将加载任务委派给它的父类加载器(parent)--ExtClassLoader;

2. ExtClassLoader 的 parent 为 null,则直接调用 BootstrapClassLoader 加载该类;

3. BootstrapClassLoader 在 jdk/jre 目录下无法找到 Test 类,因此返回的 Class 为 null;

4. 因为 parent 和 BootstrapClassLoader 都没能成功加载 Test 类,所以 AppClassLoader 会调用自身的 findClass() 方法来加载 Test 类。

最终,Test 就是被系统类加载器(AppClassLoader)加载到内存中的。

注意:“双亲委派”机制只是 Java 推荐的机制,并不是强制的机制。可以继承 java.lang.ClassLoader 类,实现自己的类加载器。如果想保持双亲委派模型,应该重写 findClass(name) 方法;如果想破坏双亲委派模型,可以重写 loadClass(name)方法。

Android 中的 ClassLoader

本质上 Android 和传统的 JVM 是一样的,也需要 ClassLoader 将目标类加载到内存,类加载器之间也复合双亲委派模型。但是在 Android 中,ClassLoader的加载细节有略微的差别。在 Android 虚拟机里是无法直接运行 .class 文件,Android 中会将所有的 .class 文件转化为一个 .dex 文件。Android 将加载 .dex 文件的实现封装在 BaseDexClassLoader 中,一般我们使用它的两个子类:PathClassLoader 和 DexClassLoader。

1. PathClassLoader

用来加载系统 apk 和被安装到手机中 apk 内的 dex 文件。它的两个构造函数如下:

参数说明:

dexPath:dex 文件路径,或者包含 dex 文件的 jar 包路径;

librarySearchpath:C/C++ native 库路径。

PathClassLoader 代码里除了这两个构造函数外就没有其它代码了。具体的实现都是在 BaseDexClassLoader 里面。

当一个 app 被安装到手机后,apk 里面的 class.dex 中的 .class 均是通过 PathClassLoader 来加载的。

2. DexClassLoader

对比 PathClassLoader 只能加载已经安装的应用的 dex 或 apk 文件,DexClassLoader 则没有此限制,可以从 SD 卡上加载包含 class.dex 的 jar 包或者是 apk 文件。这也是插件化或热修复的基础,在不需要安装应用的情况下完成需要使用的 dex 文件的加载。

DexClassLoader 的源码里只有一个构造函数,如下:

参数说明:

dexPath:包含 class.dex 的 apk,jar 文件路径,多个路径使用文件分割符(默认是“:”)分隔;

 optimizedDirectory:用来缓存优化的 dex 文件的路径,即从 apk 或 jar 文件中提取出来的 dex 文件,该路径不可以为空,且应该是私有的,有读写权限的路径。

总结

\bullet ClassLoader 是用来加载 class 文件的,不管是 jar 中还是 dex 中的 class;

\bullet Java 中的 ClassLoader 通过双亲委托来加载各自指定路径下的 class 文件;

\bullet 可以自定义 ClassLoader,一般覆盖 findClass() 方法,不建议重写 loadClass 方法;

\bullet Android 中常用的两个 ClassLoader 分别为:PathClassLoader 和 DexClassLoader。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1068248.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

好物周刊#11:远程桌面软件

https://cunyu1943.github.io https://yuque.com/cunyu1943 村雨遥的好物周刊,记录每周看到的有价值的信息,主要针对计算机领域,每周五发布。 一、项目 1. live 一个国内可直连的直播源分享项目,具有以下特点: 永…

IDEA 生成 javadoc

IDEA 生成 javadoc 在IDEA工具栏tools中,打开选项Generate JavaDoc(生成javaDoc 文件) 配置参数

【python海洋专题十三】读取多个nc文件画温度季节变化图

【python海洋专题十三】读取多个nc文件画温度季节变化图 上期内容 年平均的温度分布 本期内容 读取多个文件;拼接数据在画温度的季节分布图Part01. 使用数据 IAP 网格温度数据集 Part02. 读取nc的函数包对比 from netCDF4 import Dataset a Dataset(fileli…

华为OD机试 - 最远足迹(2022Q4 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路五、Java算法源码六、效果展示 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷)》。 刷的越多&…

设计模式14、命令模式 Command

解释说明:命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传递给调用对象。调用对象寻找可以处理该命令的合适对象,并把该命令传给相应的对象&…

Datagrip:高效数据库管理和开发

文章目录 摘要引言Datagrip的特点与优势多数据库支持强大的查询和编辑功能数据库导航和管理版本控制集成数据库安全性 Datagrip的使用方法安装和配置Datagrip查询和编辑数据数据库导航和管理版本控制和团队协作 总结参考文献 摘要 本文介绍了Datagrip作为一款强大的数据库管理…

什么是跨域资源共享(CORS)?如何在前端中处理CORS问题?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

2000至2022年中国月度植被覆盖度产品

简介: 中国区域2000至2022年月度植被覆盖度产品的空间分辨率250米,合成方式采用月最大值合成。本产品采用基于归一化植被指数(NDVI)像元二分模型,根据土地利用类型确定纯植被像元值和纯裸土像元值,计算中去…

cvpr24写作模板pdfLaTex编译器注意点小结

文章目录 1 更改作者显示 Anonymous CVPR submission2 \label标签的作用3 换行符// 与换列符&4 \medskip5 首行缩进6 插入图片6.1 单幅图片6.2 并排显示 Reference https://cvpr.thecvf.com/Conferences/2024 1 更改作者显示 Anonymous CVPR submission 这一行开头加上% …

代码检查过程中为什么需要涉及到编译呢?

作者: gentle_zhou 原文链接:代码检查过程中为什么需要涉及到编译呢?-云社区-华为云 随着大家对软件安全越来越重视,在编码阶段针对源码安全的保障也被各行各业企业研发测试运维团队与个人开发者越来越频繁的被提及,其…

【开发篇】二十、SpringBoot整合RocketMQ

文章目录 1、整合2、消息的生产3、消费4、发送异步消息5、补充:安装RocketMQ 1、整合 首先导入起步依赖,RocketMQ的starter不是Spring维护的,这一点从starter的命名可以看出来(不是spring-boot-starter-xxx,而是xxx-s…

分类预测 | MATLAB实现KOA-CNN开普勒算法优化卷积神经网络数据分类预测

分类预测 | MATLAB实现KOA-CNN开普勒算法优化卷积神经网络数据分类预测 目录 分类预测 | MATLAB实现KOA-CNN开普勒算法优化卷积神经网络数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现KOA-CNN开普勒算法优化卷积神经网络数据分类预测&#xff0…

安果计算器-您的全能计算伴侣

在日常生活、工作中,我们常常面临各种计算需求。安果计算器为您提供全面而精确的计算解决方案。 一、综 合数学功能:基础运算: 包括加、减、乘、除等基础算术功能。高级数学: 平方根、立方根、开方、随机复数、随机整数、绝对值、常用对数、自然对数、正弦、余弦、…

跨时区系统设计方案

一、背景 门店收银系统分布在澳洲、中国、新西兰,分跨不同时区,系统需要显示不同时区的时间,这是比较折腾的一件事,今天讲一下我们是怎么作的。 二、时区概念 时区 划分时区作用是为了统一时间,让各个区域12点都是…

基于BERT模型进行文本处理(Python)

基于BERT模型进行文本处理(Python) 所有程序都由Python使用Spyder运行。 对于BERT,在运行之前,它需要安装一些环境。 首先,打开Spyder。其次,在控制台中单独放置要安装的: pip install transformers pip install tor…

三维模型3DTile格式轻量化的纹理压缩和质量关系分析

三维模型3DTile格式轻量化的纹理压缩和质量关系分析 在三维模型的3DTile格式轻量化处理中,纹理压缩是一个重要环节。但是,纹理压缩和模型质量之间存在明显的关系需要权衡。以下是纹理压缩和模型质量关系的详细分析: 1、压缩率与纹理质量&…

Sklearn入门

Scikit learn 也简称 sklearn, 是机器学习领域当中最知名的 python 模块之一. Sklearn 包含了很多种机器学习的方式: Classification 分类Regression 回归Clustering 非监督分类Dimensionality reduction 数据降维Model Selection 模型选择Preprocessing 数据预处理 我们总能…

Java-包装类

这里写目录标题 包装类(Wrapper)包装类和基本数据的转换 String VS StringBuffer VS StringBuilderStringStringBufferStringBuilder 包装类(Wrapper) 针对八种基本数据类型相应的引用类型 基本数据类型包装类booleanBooleancha…

C++设计模式(1)-- 单例模式

基本概念 在一个项目中,全局范围内,某个类的实例有且仅有一个,通过这个唯一实例向其他模块提供数据的全局访问,这种模式就叫单例模式,单例模式的典型应用就是任务队列 涉及一个类多对象操作的函数有以下几个&#xff…

嵌入式基础知识-IP地址与子网划分

本篇介绍IP地址与子网划分的一些基础知识,在嵌入式开发,使用网络功能时,需要了解网络的一些基础知识。 1 IP地址 1.1 IPv4与IPv6 对比信息IPv4IPv6长度32位128位地址表示形式点分十进制冒分十六进制表示示例192.168.5.1002002:0000:0000:0…