-
-
[原创]Android类加载机制之Class.forName与ClassLoader.loadClass
-
发表于:
2019-12-12 21:37
4335
-
[原创]Android类加载机制之Class.forName与ClassLoader.loadClass
-- 前言:最近使用ClassLoader.findClass去hook类的加载时,发现有些类的加载竟然hook不到,经过一番问大牛,查资料的过程后,发现了另一个用于加载类的API,遂产生了疑问:为啥会存在两种方式去加载类呢???以下是研究所得,菜鸟一个,大牛轻喷。。。
本篇的源码基于Android 6.0.1_r77.
先看Class.forName()
路径:/libcore/libart/src/main/java/java/lang/Class.java
实际调用的是Class类的forName(String,boolean,ClassLoader)函数,这里传进去的第一个参数为类名称,第二个参数是一个boolean类型的值为true,而第三个参数就是一个ClassLoader。
继续看这个被调用的forName函数
可以看到实际上调用的就是native方法classForName函数
再来看ClassLoader.loadClass函数
路径:/libcore/libart/src/main/java/java/lang/ClassLoader.java
跟进这个loadClass(String,boolean)函数
可以看到这个函数,首先查找这个类是否已经加载过,如果没有加载,优先执行parent(参数类型也是ClassLoader)的loadClass函数,这里要引入一个ClassLoader的委托机制,即当我们通过ClassLoader A加载目标类的时候,它首先会委托自己的parent进行加载,而parent可能还会进一步地去委托自己的parent去加载,如此递进,如果被委托的Java Class对象加载不了目标类的话,则由委托者尝试加载。这里的parent应该是bootClassLoader
假设此时,如果parent加载的class为null,进一步查看findClass的内容
可以发现这里直接抛出一个异常。。。。实际上这个类的实现由其子类实现也就是BootClassLoader
可以看到实际上也调用的Class类的classForName函数;
跟踪Class的classForName函数
可以看到实际上这个函数由native层实现,查看这个函数的具体实现
路径:/art/runtime/native/java_lang_Class.cc
可以看到实际上最终这个函数调用的是ClassLinker的FindCLass去加载的java类函数,而使用Class.forName与ClassLoader.loadClass最终的不同点在于在java层最终调用Class.classForName函数时传进来的第二个参数的不同而已,我们来看这个初始化函数
路径:/art/runtime/class_linker.cc
这个函数实际上调用这个类的InitializeClass函数,类的初始化函数????
进一步查看这个函数,发现这个函数首先进行一些类的校验,然后进行父类的初始化
在父类进行初始化后,对本类的一些静态的变量进行初始化
实际上,这两个API区别在于,如果这个类被重载或者有静态变量需要初始化则会调用Class.forName函数,否则调用ClassLoader.findClass函数进行类的加载。
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2019-12-15 17:04
被Simp1er编辑
,原因: