这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战
Java-ClassLoader
Java
中类加载器主要分为两种类型:系统类加载器和自定义类加载器。
加载器 | 类名 | 介绍 |
---|---|---|
Booststap ClassLoader (引导类加载器) | C/C++编写没有Java类 | 它是由C/C++编写的。主要是用来加载JDK核心代码库。例如java.lang、java.uti等系统类 |
Extensions ClassLoader (拓展类加载器) | ExtClassLoader | 用于加载Java拓展类,提供系统类之外的额外功能 |
Application ClassLoader (应用程序加载器) | AppClassLoader | 可以称为System ClassLoader 用于加载目录类库 |
Custom ClassLoader (自定义类加载器) | 继承ClassLoader | 自定义加载器是通过继承ClassLoader实现自定义功能类加载器 |
ClassLoader继承关系
ClassLoader
继承关系如下所示,Java中编写带main()函数
的类是继承自AppClassLoader;AppClassLoader
的父加载器是ExtClassLoader
。而ExtClassLoader
的父加载器是Booststap ClassLoader
,但由于是C/C++编写没有Java类;
classDiagram
ClassLoader <|-- SecureClassLoader
SecureClassLoader <|-- URLClassLoader
URLClassLoader <|-- ExtClassLoader
URLClassLoader <|-- AppClassLoader
加载过程-双亲委托模式
类加载器查找类采用双亲委托模式,就是首先判断该类是否已经载入:如果没有载入就委托父加载器进行查找,进行递归操作直到委托到最顶层Booststap ClassLoader
,如果查找到了就直接返回,没有找到依次向下查找,若找不到最后交给自己去查找。
具体原理步骤
- 一个类加载器收到类加载请求,首先会把请求委托给父类加载器执行。
- 如果父类还存在父类接在其,则继续向上委托,直到顶层
Booststap ClassLoader
为止。 - 如果父类加载器可以加载就返回结果,如果父类加载失败则由子类自己尝试加载,子类加载失败抛出
ClassNotFoundException
异常。
Android-ClassLoader
Java
中的ClassLoader
可以加载jar包和Class文件,而在Android
中并不支持在Android虚拟机中加载的是dex文件。因此对于Android的ClassLoader
并不能和Java的ClassLoader
相通。而Android的ClassLoader
分类类型其实和Java类似,同样也是系统类加载器和自定义类加载器两种。
加载器 | 类名 | 介绍 |
---|---|---|
BootClassLoader | BootClassLoader | BootClassLoader是Android系统用来加载常用类的加载器,不同点在于它不是用C/C++代码实现,而是Java代码。 |
DexClassLoader | DexClassLoader | 用于加载dex文件以及含有dex文件的压缩包 |
PathClassLoader | PathClassLoader | PathClassLoader用来加载系统类和应用程序类 |
ClassLoader继承关系
classDiagram
ClassLoader <|-- BootClassLoader
ClassLoader <|-- BaseDexClassLoader
ClassLoader <|-- SecureClassLoader
SecureClassLoader <|-- URLClassLoader
BaseDexClassLoader <|-- InMemoryDexClassLoader
BaseDexClassLoader <|-- PathClassLoader
BaseDexClassLoader <|-- DexClassLoader
加载过程
Android
的ClassLoader
同样也是双亲委托模式。
ClassLoader
使用loadClass
方法加载类loadClass
调用findClass
方法然后调用到DexPathList
的findClass
方法;遍历加载过的所有dex文件,再调用loadClassBinaryName
方法去加载需要加载的类;loadClassBinaryName
调用Native
方法defineClass
加载类。最后ClassLoader
创建和加载过程就完成了。
// #ClassLoader.loadClass
public Class<?> loadClass(String className) throws ClassNotFoundException {
return loadClass(className, false);
}
protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
Class<?> clazz = findLoadedClass(className);
if (clazz == null) {
ClassNotFoundException suppressed = null;
try {
clazz = parent.loadClass(className, false);
} catch (ClassNotFoundException e) {
suppressed = e;
}
if (clazz == null) {
try {
clazz = findClass(className);
} catch (ClassNotFoundException e) {
e.addSuppressed(suppressed);
throw e;
}
}
}
return clazz;
}
// #ClassLoader.findClass
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Class clazz = pathList.findClass(name);
if (clazz == null) {
throw new ClassNotFoundException(name);
}
return clazz;
}
// #DexPathList.findClass
public Class findClass(String name) {
for (Element element : dexElements) {
DexFile dex = element.dexFile;
if (dex != null) {
Class clazz = dex.loadClassBinaryName(name, definingContext);
if (clazz != null) {
return clazz;
}
}
}
return null;
}
// #DexPathList.loadClassBinaryName
public Class loadClassBinaryName(String name, ClassLoader loader) {
return defineClass(name, loader, mCookie);
}
private native static Class defineClass(String name, ClassLoader loader, int cookie);