类加载原理做为程序运行的基础,一直在程序的背后默默的付出。现在Android
中的插件化、热修复等动态加载技术的实现也都涉及到了类加载的原理。关于类加载的相关知识我之前也是遇到一点看一点,没有完整的详细的了解过,最近有时间专门对这块知识进行了学习,因而这里作一个总结。java
一个类从.class
文件被加载到内存,到在内存中使用,最后从内存中卸载,这是一个完整的生命周期过程。不过在得到.class
文件以前,咱们编码时的文件格式仍是.java
文件格式,还记得刚学Java
时学到过在完成编码以后要先执行javac
命令进行编译,编译生成对应的.class
文件,以后再经过java
命令执行Java
程序。不过当时只知道是先编译再运行,并不知道究竟是怎么运行的谁去运行的。程序员
其实一个类从.class
文件被加载到内存到从内存中卸载,整个生命周期一共通过如下几个阶段:数组
在加载阶段虚拟机主要完成如下三件事情:安全
java.lang.Class
对象,做为方法区这个类的各类数据的访问入口。这个简单的来讲加载阶段主要就是将类的.class
文件做为二进制字节流读入内存,而且在内存中实例化一个java.lang.Class
对象以便后续访问。在这个阶段中.class
文件二进制字节流的读取来源没有太多限制,能够很是灵活。好比能够从本地系统中读取、能够从jar
包中读取、能够从网络下载等等。bash
验证是链接阶段中的第一步,主要的做用是保证Class
文件的字节流中包含的信息符合当前虚拟机的要求,而且不会危害虚拟机的自身安全。在验证阶段大体会完成如下四个检验操做:markdown
Class
文件格式的规范,而且能被当前版本的虚拟机处理。Java
语言规范的要求。从以上几个操做能够看出,这个阶段主要就是将二进制字节流进行一个合法验证,包括文件格式、语义、数据流控制流和符号引用等。保证不会出现相似文件格式错误、继承了被final
修饰的类、指令跳转错误、类型转换错误、修饰符访问性等等错误状况。cookie
准备阶段中主要是为类中静态变量在方法区里分配内存而且设置类变量的初始值。这里的初始值即零值。具体以下:网络
数据类型 | 零值 |
---|---|
int | 0 |
long | 0L |
short | (short)0 |
char | '\u0000' |
byte | (byte)0 |
boolean | false |
float | 0.0f |
double | 0.0d |
reference | null |
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动做主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调试限定符7类符号引用进行。数据结构
初始化阶段中真正开始执行类中定义的Java
程序代码,为全部类变量进行赋值,执行静态代码块。app
从上面的类加载过程能够看出在初始化阶段之前除了加载阶段,其他阶段都是由虚拟机主导控制。而在加载阶段能够经过自定义类加载器进行参与。类加载器顾名思义是用来加载类的,负责将类的.class
文件转换成内存中类的二进制字节流。Java
中的类加载器按类型分有两种:系统类加载器和自定义类加载器。其中系统类加载器有主要有三种,分别是:引导类加载器(Bootstrap ClassLoader
)、拓展类加载器(Extensions ClassLoader
)和应用程序类加载器(Application ClassLoader
)。
Bootstrap ClassLoader
)这个类加载器是用C/C++
语言实现的,用来加载JDK
中的核心类,主要加载$JAVA_HOME/jre/lib
目录下的类,例如rt.jar
、resources.jar
等包中的类。
Extensions ClassLoader
)这个类加载器是用Java
语言实现的,实现类为ExtClassLoader
,用来加载Java
的拓展类,主要加载$JAVA_HOME/jre/lib/ext
目录和系统属性java.ext.dir
所指定的目录。
Application ClassLoader
)这个类加载器是用Java
语言实现的,实现类为AppClassLoader
,能够经过ClassLoader.getSystemClassLoader
方法获取到,主要加载Classpath
目录和系统属性java.class.path
指定的目录下的类。
public class ClassLoaderDemo { public static void main(String[] args) { ClassLoader classLoader = ClassLoaderDemo.class.getClassLoader(); while (classLoader != null) { System.out.println("ClassLoader:" + classLoader); classLoader = classLoader.getParent(); } } } 复制代码
这里新建一个Java
类ClassLoaderDemo
,循环打印其类加载器和父类加载器,控制台输出结果以下。
从结果能够看出ClassLoaderDemo
类的类加载器是AppClassLoader
,AppClassLoader
的父类加载器是ExtClassLoader
,而ExtClassLoader
的父类加载器就为null
了,这是由于ExtClassLoader
的父类加载器BootstrapClassLoader
是由C/C++
语言实现的,因此在Java
中没法获取到它的引用。接下来再进入源码来看一下,先看AppClassLoader
。
static class AppClassLoader extends URLClassLoader {
......
}
复制代码
查看源码发现AppClassLoader
的父类并非ExtClassLoader
而是URLClassLoader
,再看ExtClassLoader
。
static class ExtClassLoader extends URLClassLoader {
......
}
复制代码
ExtClassLoader
的父类也是URLClassLoader
进而再看URLClassLoader
。
public class URLClassLoader extends SecureClassLoader implements Closeable {
......
}
public class SecureClassLoader extends ClassLoader {
......
}
public abstract class ClassLoader {
......
}
复制代码
URLClassLoader
的父类是SecureClassLoader
,而SecureClassLoader
的父类是ClassLoader
,ClassLoader
是一个抽象类。经过对源码的跟踪发现,彷佛这里的继承关系与控制台输出的结果不太一致。因而进一步去看输出ClassLoaderDemo
中调用的ClassLoader.getParent()
方法源码。
public final ClassLoader getParent() { if (parent == null) return null; SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkClassLoaderPermission(parent, Reflection.getCallerClass()); } return parent; } // The parent class loader for delegation // Note: VM hardcoded the offset of this field, thus all new fields // must be added *after* it. private final ClassLoader parent; 复制代码
ClassLoader
的getParent
方法中看到返回的是一个成员变量中的parent
,他是一个ClassLoader
类型对象。继续跟踪寻找它是在哪里初始化赋值的。
private ClassLoader(Void unused, ClassLoader parent) { this.parent = parent; if (ParallelLoaders.isRegistered(this.getClass())) { parallelLockMap = new ConcurrentHashMap<>(); package2certs = new ConcurrentHashMap<>(); domains = Collections.synchronizedSet(new HashSet<ProtectionDomain>()); assertionLock = new Object(); } else { // no finer-grained lock; lock on the classloader instance parallelLockMap = null; package2certs = new Hashtable<>(); domains = new HashSet<>(); assertionLock = this; } } protected ClassLoader(ClassLoader parent) { this(checkCreateClassLoader(), parent); } protected ClassLoader() { this(checkCreateClassLoader(), getSystemClassLoader()); } 复制代码
跟踪查看源码发现父类加载器parent
是在ClassLoader
的构造函数时传入的,若是没有传入默认调用getSystemClassLoader
方法获取一个父类加载器。接下来继续查看getSystemClassLoader
方法。
public static ClassLoader getSystemClassLoader() { initSystemClassLoader(); if (scl == null) { return null; } SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkClassLoaderPermission(scl, Reflection.getCallerClass()); } return scl; } 复制代码
getSystemClassLoader
方法中又调用了initSystemClassLoader
方法初始化系统类加载器,方法最后将这个类加载器scl
返回。继续查看initSystemClassLoader
方法。
private static synchronized void initSystemClassLoader() { if (!sclSet) { if (scl != null) throw new IllegalStateException("recursive invocation"); sun.misc.Launcher l = sun.misc.Launcher.getLauncher(); if (l != null) { Throwable oops = null; scl = l.getClassLoader(); ....... } 复制代码
这个方法中获取到Launcher
以后调用了Launcher
的getClassLoader
方法获取到建立的类加载器,因而再到Launcher
中查看。
public ClassLoader getClassLoader() { return this.loader; } 复制代码
Launcher
的getClassLoader
方法中返回了其成员变量中的loader
对象,因而再去寻找这个对象的建立。
public Launcher() { Launcher.ExtClassLoader var1; try { var1 = Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try { this.loader = Launcher.AppClassLoader.getAppClassLoader(var1); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9); } ...... } 复制代码
在Launcher
的构造函数里找到,这里是经过Launcher.AppClassLoader.getAppClassLoader(var1)
方法建立的loader
,因而再进入查看。
public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException { final String var1 = System.getProperty("java.class.path"); final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1); return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() { public Launcher.AppClassLoader run() { URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2); return new Launcher.AppClassLoader(var1x, var0); } }); } 复制代码
getAppClassLoader
方法中最终new
了一个AppClassLoader
返回,这就又回到了AppClassLoader
的构造方法。以前看过构造传入的第二个参数就是parent
父类加载器,这里传入的var0
能够看到就是ExtClassLoader
类型。
总结来讲ClassLoader
的父子关系并非由继承实现的,A
是B
的父类加载器,并不表示B
继承了A
,每一个CLassLoader
中保存了一个它的父类加载器的引用,经过getParent
方法得到的就是它的值,它是在类加载器建立时构造函数中进行赋值的。若是构造中没有传入父类加载器默认调用getSystemClassLoader
方法获取系统类加载器,经过查看发现默认系统类加载器就是AppClassLoader
。在Launcher
的构造方法中,会依次建立ExtClassLoader
和AppClassLoader
,此时ExtClassLoader
做为父类加载器由构造函数传入AppClassLoader
。实际的类加载继承关系以下图。
在一些特殊需求场景下可能须要程序员自定义类加载器。例如从网络下载一个加密过的.class
类文件,此时就须要自定义类加载器,先进行文件解密再进行类加载。下面就来模拟一下这个例子,先定义一个测试类TestPrint
。
public class TestPrint { public void printString() { System.out.println("测试输出字符串"); } } 复制代码
使用javac
命令编译生成TestPrint.class
文件。
Base64
加密,将编译生成的
.class
文件转成二进制字节流加密后再保存成本地文件。
public class Test { public static void main(String[] args) { byte[] classBytes = FileIOUtils.readFile2BytesByStream("/Users/sy/Downloads/ClassLoader/TestPrint.class"); FileIOUtils.writeFileFromBytesByStream("/Users/sy/Downloads/ClassLoader/TestPrint.class",Base64.getEncoder().encode(classBytes)); } } 复制代码
获得加密后的TestPrint.class
后接下来编写自定义的类加载器MyClassLoader
。
public class MyClassLoader extends ClassLoader { private String path; protected MyClassLoader(String path) { this.path = path; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class aClass = null; // 获取二进制字节流 byte[] classBytes = loadClassBytes(name); if (classBytes == null) { System.out.println("class data is null"); } else { aClass = defineClass(name, classBytes, 0, classBytes.length); } return aClass; } private byte[] loadClassBytes(String name) { String fileName = getFileName(name); File file = new File(path, fileName); InputStream inputStream = null; ByteArrayOutputStream outputStream = null; try { inputStream = new FileInputStream(file); outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while ((len = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } return outputStream.toByteArray(); } catch (Exception e) { e.printStackTrace(); } finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } private String getFileName(String name) { String fileName; int index = name.lastIndexOf("."); if (index == -1) { fileName = name + ".class"; } else { fileName = name.substring(index + 1) + ".class"; } return fileName; } } 复制代码
自定义类加载器分为如下几个步骤:
ClassLoader
。findClass
方法。findClass
方法中获取到二进制字节流后,调用defineClass
方法。在MyClassLoader
的findClass
方法中首先读取到本地硬盘下的TestPrint.class
文件的字节流,而后调用defineClass
方法,该方法会将字节流转化为Class
类型。最后写一个测试类调用。
public class TestMyClassLoader { public static void main(String[] args) { // 初始化类加载器 MyClassLoader myClassLoader = new MyClassLoader("/Users/sy/Downloads/ClassLoader"); try { // 使用自定义类加载器获取Class Class<?> printTest = myClassLoader.loadClass("TestPrint"); // 建立实例 Object instance = printTest.newInstance(); System.out.println("classloader:" + instance.getClass().getClassLoader()); Method method = printTest.getDeclaredMethod("printString", null); method.setAccessible(true); method.invoke(instance, null); } catch (Exception e) { e.printStackTrace(); } } } 复制代码
运行结果:
Base64
加密,须要在
defineClass
前进行一个解码操做,修改
findClass
方法。
@Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class aClass = null; // 获取二进制字节流 byte[] classBytes = loadClassBytes(name); // Base64 decode classBytes = Base64.getDecoder().decode(classBytes); if (classBytes == null) { System.out.println("class data is null"); } else { aClass = defineClass(name, classBytes, 0, classBytes.length); } return aClass; } 复制代码
再次运行查看结果:
学习类加载器就避免不了要了解双亲委托,它是类加载器寻找加载类的模式。仍是先看到以前自定义类加载器的例子,自定义时复写了findClass
方法,可是使用时却没有直接调用这个方法,使用时是经过ClassLoader.loadClass
方法得到Class
的。双亲委托模式就是在这个方法中实现的,因而进入查看源码。
public Class<?> loadClass(String name) throws ClassNotFoundException { return loadClass(name, false); } protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 首先检查该类是否加载过 Class<?> c = findLoadedClass(name); // c为空说明没有加载过 if (c == null) { long t0 = System.nanoTime(); try { // 判断是否有父类加载器 if (parent != null) { // 有父类加载器就调用父类加载器的loadClass方法 c = parent.loadClass(name, false); } else { // 没有父类加载器就调用这个方法 // 方法中会调用native方法findBootstrapClass使用BootstrapClassLoader检查该类是否已加载 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } // 走到此处c还为null说明父类加载器没有加载该类 if (c == null) { long t1 = System.nanoTime(); // 就调用自身的findClass查找加载该类 c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } } 复制代码
loadClass
中的代码逻辑很是清晰的描述了双亲委托模式,首先经过findLoadedClass
方法检验要加载的类是否被加载过。加载过直接返回该类的Class
对象,没加载过则c
为空进入下面的判断,判断父类加载器parent
是否为空,不为空调用父类的loadClass
方法,为空则调用findBootstrapClassOrNull
方法,该方法中会继续调用native
方法findBootstrapClass
使用BootstrapClassLoader
检查该类是否已加载。接着若是没有加载该类就会调用自身的findClass
方法查找加载该类。
最后对双亲委托模式作个总结:双亲委托模式是指类加载器加载一个类首先是判断这个类是否加载过,没加载过不会本身直接加载,而是委托给其父类加载器去查找,一直委托到顶层引导类加载器BootstrapClassLoader
,若是BootstrapClassLoader
找到该Class
就会直接返回,没找到就会交给子类加载器依次向下查找,一直没找到最后就会交给自身去查找。
双亲委托模式有两个好处:
Class
。java.lang.Object
类不管使用哪一个类加载器加载,最终都会委托给顶层BootstrapClassLoader
来加载,这样保证了Object
类永远是同一个类,不会出现多个不一样的Object
类。这样也没法经过自定义一个Object
类替换系统原来的Object
类。另外Java
虚拟机判断两个类是同一个类,是依据两个类类名一致,而且被同一个类加载器加载。这里能够在以前的自定义类加载器的基础上测试下。将原来的MyClassLoader
复制后重命名YourClassLoader
一份,再编写一个测试类。
public class TestDifferentClassLoader { public static void main(String[] args) { MyClassLoader myClassLoader = new MyClassLoader("/Users/sy/Downloads/ClassLoader/"); YourClassLoader yourClassLoader = new YourClassLoader("/Users/sy/Downloads/ClassLoader/"); try { Class<?> myPrintTest = myClassLoader.loadClass("TestPrint"); // 使用不一样的类加载器 Class<?> yourPrintTest = yourClassLoader.loadClass("TestPrint"); Object myInstance = myPrintTest.newInstance(); Object yourInstance = yourPrintTest.newInstance(); System.out.println(myInstance.getClass().equals(yourInstance.getClass())); System.out.println(myInstance.getClass().getName()); System.out.println(yourInstance.getClass().getName()); } catch (Exception e) { e.printStackTrace(); } } } 复制代码
运行结果:
public class TestDifferentClassLoader { public static void main(String[] args) { MyClassLoader myClassLoader = new MyClassLoader("D:\\"); YourClassLoader yourClassLoader = new YourClassLoader("D:\\"); try { Class<?> myPrintTest = myClassLoader.loadClass("TestPrint"); // 用同一个类加载器 Class<?> yourPrintTest = myClassLoader.loadClass("TestPrint"); Object myInstance = myPrintTest.newInstance(); Object yourInstance = yourPrintTest.newInstance(); System.out.println(myInstance.getClass().equals(yourInstance.getClass())); System.out.println(myInstance.getClass().getName()); System.out.println(yourInstance.getClass().getName()); } catch (Exception e) { e.printStackTrace(); } } } 复制代码
运行结果:
Android
中类加载器与Java
中的类加载器相似可是并不彻底相同。Java
中类加载器是加载.class
文件,而Android
中是加载的dex
文件,不过Android
中也分系统类加载器和自定义类加载器,系统类加载器主要包括如下三种:BootClassLoader
、DexClassLoader
和PathClassLoader
。这里仍是先循环打印一下Android
中的父类加载器。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ClassLoader classLoader = MainActivity.class.getClassLoader(); while (classLoader != null) { Log.d("classLoader", "name:" + classLoader); classLoader = classLoader.getParent(); } } } 复制代码
运行日志结果:
从日志能够看到这里有两个类加载器,一个是BootClassLoader
另外一个是PathClassLoader
。Android
中的每一个类加载器里一样保存一个父类加载器的引用,getParent
方法获取到的一样是这个ClassLoader
,仍是先来看一下Android
中的ClassLoader
类。
public abstract class ClassLoader { private final ClassLoader parent; ...... 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) { // 父类加载器不为空则调用其的loadClass方法 c = parent.loadClass(name, false); } else { // 父类加载器为空就调用findBootstrapClassOrNull方法 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // 父类加载器没有查找到该类,则调用自身findClass方法查找加载 c = findClass(name); } } return c; } private Class<?> findBootstrapClassOrNull(String name) { return null; } public final ClassLoader getParent() { return parent; } ...... } 复制代码
Android
中的ClassLoader
类一样是一个抽象类,它的loadClass
方法中的逻辑和Java
中的相似,一样是遵循了双亲委托模式,父类加载器不为空则调用父类加载器的loadClass
方法,为空则调用findBootstrapClassOrNull
方法,该方法这里直接返回的null
。若父类加载器没有查找到须要加载的类,则调用自身的findClass
方法。
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
复制代码
接着看到ClassLoader
中的findClass
里是直接抛出了一个ClassNotFoundException
异常,说明这个方法须要子类来实现。那么接下来就来看看Android
中类加载器的实际继承关系。
抽象类ClassLoader
定义了类加载器的主要功能,它的子类如上图。先根据源码梳理下它们之间的关系。
public class BaseDexClassLoader extends ClassLoader {
......
}
public class SecureClassLoader extends ClassLoader {
......
}
public class DexClassLoader extends BaseDexClassLoader {
......
}
public class PathClassLoader extends BaseDexClassLoader {
......
}
public final class InMemoryDexClassLoader extends BaseDexClassLoader {
......
}
public class URLClassLoader extends SecureClassLoader implements Closeable {
......
}
public final class DelegateLastClassLoader extends PathClassLoader {
......
}
复制代码
除了这些子类,抽象类ClassLoader
中还有一个内部类BootClassLoader
。
class BootClassLoader extends ClassLoader {
......
}
复制代码
综上所述Android
中类加载器的继承关系以下图。
接下来简单了解一下这些类加载器。
class BootClassLoader extends ClassLoader { private static BootClassLoader instance; @FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED") public static synchronized BootClassLoader getInstance() { if (instance == null) { instance = new BootClassLoader(); } return instance; } public BootClassLoader() { super(null); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { return Class.classForName(name, false, null); } ...... @Override protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { Class<?> clazz = findLoadedClass(className); if (clazz == null) { clazz = findClass(className); } return clazz; } ...... } 复制代码
BootClassLoader
是ClassLoader
的内部类继承自ClassLoader
,而且提供了一个获取单例的getInstance
方法。与Java
中不一样BootClassLoader
不是用C/C++
实现的是用Java
实现的,Android
系统启动时会使用BootClassLoader
来预加载经常使用类。
public class DexClassLoader extends BaseDexClassLoader {
public DexClassLoader(String dexPath, String optimizedDirectory,
String librarySearchPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), librarySearchPath, parent);
}
}
复制代码
DexClassLoader
看名字就知道是用来加载dex
文件的,它的构造函数中有四个参数:
dex
相关文件路径集合。dex
文件存储路径。C/C++
库的路径集合。DexClassLoader
继承自BaseDexClassLoader
其主要的方法都在其父类中实现。
public class PathClassLoader extends BaseDexClassLoader {
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
public PathClassLoader(String dexPath, String librarySearchPath, ClassLoader parent) {
super(dexPath, null, librarySearchPath, parent);
}
}
复制代码
PathClassLoader
是用来加载系统类和应用程序的类,一样继承自BaseDexClassLoader
类, 它的构造函数里没有optimizedDirectory
参数,一般用来加载已经安装的dex
文件。
BaseDexClassLoader
是DexClassLoader
和PathClassLoader
的父类。
public class BaseDexClassLoader extends ClassLoader { private final DexPathList pathList; ...... public BaseDexClassLoader(String dexPath, File optimizedDirectory, String librarySearchPath, ClassLoader parent) { super(parent); this.pathList = new DexPathList(this, dexPath, librarySearchPath, null); if (reporter != null) { reporter.report(this.pathList.getDexPaths()); } } ...... @Override protected Class<?> findClass(String name) throws ClassNotFoundException { List<Throwable> suppressedExceptions = new ArrayList<Throwable>(); Class c = pathList.findClass(name, suppressedExceptions); if (c == null) { ClassNotFoundException cnfe = new ClassNotFoundException( "Didn't find class \"" + name + "\" on path: " + pathList); for (Throwable t : suppressedExceptions) { cnfe.addSuppressed(t); } throw cnfe; } return c; } ....... } 复制代码
在它的构造方法中先是建立了一个DexPathList
对象,接着它的findClass
方法中是经过pathList.findClass
方法得到的Class
对象。
public Class<?> findClass(String name, List<Throwable> suppressed) { for (Element element : dexElements) { Class<?> clazz = element.findClass(name, definingContext, suppressed); if (clazz != null) { return clazz; } } if (dexElementsSuppressedExceptions != null) { suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions)); } return null; } 复制代码
findClass
方法中循环遍历了dexElements
数组,再经过Element.findClass
方法来得到Class
对象,Element
又是DexPathList
的内部类,进一步找到它的findClass
方法查看。
public Class<?> findClass(String name, ClassLoader definingContext, List<Throwable> suppressed) { return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed) : null; } 复制代码
这个方法中又调用了DexFile
的loadClassBinaryName
方法。
public Class loadClassBinaryName(String name, ClassLoader loader, List<Throwable> suppressed) { return defineClass(name, loader, mCookie, this, suppressed); } private static Class defineClass(String name, ClassLoader loader, Object cookie, DexFile dexFile, List<Throwable> suppressed) { Class result = null; try { result = defineClassNative(name, loader, cookie, dexFile); } catch (NoClassDefFoundError e) { if (suppressed != null) { suppressed.add(e); } } catch (ClassNotFoundException e) { if (suppressed != null) { suppressed.add(e); } } return result; } 复制代码
loadClassBinaryName
方法里继续调用了defineClass
方法,而defineClass
方法里最终调用了defineClassNative
这个native
方法加载dex
文件。
Android
系统启动后init
进程会启动Zygote
进程,Zygote
进程初始化时会预加载经常使用类,进而会调用Class.forName
方法,该方法里会经过BootClassLoader.getInstance
方法建立BootClassLoader
。以后Zygote
进程又会启动SystemServer
进程,进而又会经过PathClassLoaderFactory
建立PathClassLoader
。总而言之,Android
中的这两个类加载器在启动时就进行初始化建立了。
Java
中类加载生命周期包括:加载、链接、初始化、使用、卸载这些阶段,其中链接阶段又分为验证、准备、解析。Java
中的 系统类加载器与Android
中的系统类加载器并不相同,但都遵循了双亲委托模式。ClassLoader
类复写它的findClass
方法实现本身的类加载器。