ClassLoader类加载源码解析
作者:droidDing 发布时间:2023-11-25 18:17:09
标签:ClassLoader,类加载
Java类加载器
1、BootClassLoader: 用于加载Android Framework层class文件。
2、PathClassLoader: 用于Android应用程序类加载器。可以加载指定的dex,jar、zip、zpk中的classes.dex
3、DexClassLoader:加载指定的dex,以及jar、zip、apk中的classes.dex
源码解析
1.ClassLoader中提供loadClass用于加载指定类
//ClassLoader.java
public Class<?> loadClass(String name) throws ClassNotFoundException {
//该处调用了两个参数的重载方法
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
//先查一下该类是否已经加载过了
Class<?> c = findLoadedClass(name);
if (c == null) {
try {
//双亲委托机制,先让爸爸去找
if (parent != null) {
c = parent.loadClass(name, false);
} else {
//如果parent为null,则用BootClassLoader进行加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
//如果都找不到就自己去找,此方法在子类BaseDexClassLoader类中有重写
c = findClass(name);
}
}
return c;
}
2.BaseDexClassLoader类中对findClass有重写,也是实际会使用执行的
//BaseDexClassLoader.java
//查找class
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
...
//这里通过pathList变量来查找,而pathList是在BaseDexClassLoader的构造方法中初始化的
Class c = pathList.findClass(name, suppressedExceptions);
...
return c;
}
private final DexPathList pathList;
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String librarySearchPath, ClassLoader parent, boolean isTrusted) {
super(parent);
//构造方法中初始化pathList变量
this.pathList = new DexPathList(this, dexPath, librarySearchPath, null, isTrusted);
}
3.BaseDexClassLoader中是通过调用DexPathList中的findClass来实现的,那么接下来我们分析一下DexPathList是怎么实现的
//DexPathList.java
//是一个Element数组,一个element中包含一个 DexFile,DexFile就代表一个Dex文件,里面的native(C/C++)函数来进行Dex的加载工作
private Element[] dexElements;
public Class<?> findClass(String name, List<Throwable> suppressed) {
for (Element element : dexElements) {
//此处调用Element的findClass来实现,
Class<?> clazz = element.findClass(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
return null;
}
// Element为DexPathList的内部类
static class Element {
private final File path;
//一个DexFile就代表一个Dex文件
private final DexFile dexFile;
//有多个构造方法,但都仅是将值传过来,让Element来持有一个DexFile
public Element(DexFile dexFile) {
this.dexFile = dexFile;
this.path = null;
}
public Class<?> findClass(String name, ClassLoader definingContext,
List<Throwable> suppressed) {
//通过DexFile来加载类
return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed)
: null;
}
}
DexPathList(ClassLoader definingContext, String dexPath,
String librarySearchPath, File optimizedDirectory, boolean isTrusted) {
//通过makeDexElements方法为dexElements初始化
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory,
suppressedExceptions, definingContext, isTrusted);
}
//腾讯系的热修复,诸如微信tinker、qq空间qfix原理便是反射此方法,将修复后的类打包成dex,通过反射该方法来将文件转化为Element,并将新生成的element放到dexElements前面,这样下次系统再去寻找某个class时,会先从修复后的dex中来找class,找到后便不再继续查找,从而修复该class,此方式便为插桩
private static Element[] makeDexElements(List<File> files, File optimizedDirectory,
List<IOException> suppressedExceptions, ClassLoader loader, boolean isTrusted) {
Element[] elements = new Element[files.size()];
...
for (File file : files) {
if (name.endsWith(DEX_SUFFIX)) {
//以 .dex 结尾的
// Raw dex file (not inside a zip/jar).
//加载dex文件
dex = loadDexFile(file, optimizedDirectory, loader, elements);
if (dex != null) {
elements[elementsPos++] = new Element(dex, null);
}
}
}
...
return elements;
}
private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader,
Element[] elements)
throws IOException {
if (optimizedDirectory == null) {
return new DexFile(file, loader, elements);
} else {
String optimizedPath = optimizedPathFor(file, optimizedDirectory);
return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader, elements);
}
}
4.这里通过 new DexFile 或者 loadDex方法来创建DexFile,两者类似,那我们拿new DexFile 来举例分析
//DexFile.java
private DexFile(String sourceName, String outputName, int flags, ClassLoader loader,
DexPathList.Element[] elements) throws IOException {
...
//此处调用openDexFile来实现
mCookie = openDexFile(sourceName, outputName, flags, loader, elements);
...
}
private static Object openDexFile(String sourceName, String outputName, int flags,
ClassLoader loader, DexPathList.Element[] elements) throws IOException {
//此处通过调用 openDexFileNative来实现
return openDexFileNative(new File(sourceName).getAbsolutePath(),
(outputName == null)
? null
: new File(outputName).getAbsolutePath(),
flags,
loader,
elements);
}
//openDexFileNative是一个native方法,是由C/C++来实现的
private static native Object openDexFileNative(String sourceName, String outputName, int flags,
ClassLoader loader, DexPathList.Element[] elements);
来源:https://blog.csdn.net/qq_23081779/article/details/91946548


猜你喜欢
- 页面拖动到最后一页 再向下滑动回复到 第一页,第一页向前滑动回到 最后一页同时,底部红色小圆点随着页面的滑动距离比例随时改变位置布局:<
- 接口的灵活性就在于“规定一个类必须做什么,而不管你如何做”。我们可以定义一个接口类型的引用变量来引用实现接口的类的实例,当这个引用调用方法时
- Java获取文件的类型和扩展名实现代码:File file=new File("E:\\aa.jpg"); String
- 开发环境:android4.1.1实验功能:在第一个Hello World!为标签的activity中显示good,该界面中有一个名为Nex
- C++ 中const修饰虚函数实例详解【1】程序1#include <iostream>using namespace std;
- 前言如今,企业级应用程序的高性能安全加密的常见场景是同时支持HTTP和HTTPS两种协议,这篇文章考虑如何让Spring Boot应用程序同
- 起因我们先来看一个报错报错很简单,参数 start 没找到。我是在实现一个 API 接口时发现了一个问题,当我不使用 @Param 标签时,
- Dictionary<TKey,TValue> 类,表示键和值的集合。Dictionary<TKey,TValue>
- 有人在社区问到:C#调用Oracle中自定义函数的返回值时,无法正常调用。但在PL/SQL中正常调用返回。于是动手一试:1、准备函数(Ora
- 本文实例讲述了C#计算程序执行过程花费时间的方法。分享给大家供大家参考。具体如下:计算执行完程序花费的时间:void AddInfo(){
- 在使用C#进行桌面应用开发中,经常会有对文件进行操作的情况,这时可能会需要对文件夹进行文件扫描,获取所有文件做法如下/// <summ
- 上一集中我们说到需要用Java来制作一个知乎爬虫,那么这一次,我们就来研究一下如何使用代码获取到网页的内容。首先,没有HTML和CSS和JS
- 1、配置maven环境变量,将maven安装的bin⽬录添加到path路径中(此电脑->属性->高级系统设置->环境变量-
- 本文实例讲述了Android AutoCompleteTextView控件基本用法。分享给大家供大家参考,具体如下:当输入部分内容之后会有相
- 本文解析了C# KeyUp事件中MessageBox的回车(Enter)键出现回调问题的解决办法。具体问题如下:在一个窗体上有一个名为txt
- 本文实例为大家分享了WPF实现3D翻牌式倒计时的具体代码,供大家参考,具体内容如下实现效果如下:思路:使用自定义控件,设置一个背板 MyCa
- 1.什么是虚函数?用virtual 修饰的成员函数叫虚函数小知识: 没有虚构造函数
- 1. 概述JDK * 是利用java反射机制 生成一个实现接口的匿名类, 在调用具体方法前调用InvocationHandler来处理Cg
- 多表联合查询resultType的返回值一般数据按参数类型返回<select id="queryCarIdList"
- Java 7的这个新特性改变了警告的对象。构建这些类型毕竟有破坏类型安全的风险,这总得有人知道。但 API 的用户对此是无能为力的,不管do