文章目录
1. 类加载与反射
1.1 类加载机制
类的加载是指将类的.class文件
读入到内存中,并为之创建一个java.lang.Class
对象,该过程由类加载器(ClassLoader)
完成。类的加载过程包含类的加载
、类的连接
和类的初始化
三个过程,当程序主动使用某个类时,如果该类还未被加载到内存中,系统就会通过这三个步骤来对该类进行初始化。因此,类的加载过程又可称为类的初始化过程,整个过程大致如下图所示:
1.1.1 类加载器
类加载器负责将类的.class文件
字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class
对象。类加载器负责加载所有的类,一旦一个类被载入JVM中,同一个类就不会再次载入。类加载器通常无法等到首次使用该类时才加载类,Java虚拟机规范允许系统预先加载某些类,当然在Android中也会支持预先加载。由于Android虚拟机并没有遵循Java虚拟机规范,因此它们的类加载器并不相同,接下来我们具体分析。
1.1.1.1 Java中的ClassLoader
Java中的类加载器主要由两种类型,即系统类加载器和自定义类加载器,其中,系统类加载器由Bootstap ClassLoader(引导类加载器)
、Extension ClassLoader(扩展类加载器)
和Application ClassLoader(应用程序类加载器)
组成,而自定义类加载器为通过继承java.lang.ClassLoader
类的方式实现。它们之间的"继承"关系为:
需要注意的是,上述的“继承”关系并非我们理解的父类与子类继承关系,这里的“继承”是指类加载器的层级。因为引导类加载器
是由C/C++编写,是JVM自带的类加载器,负责Java平台核心库,而扩展类加载器
也没有继承引导类加载器,而是继承于java.lang.ClassLoader
类,同理系统类加载器
也不是继承扩展类加载器,也是继承于java.lang.ClassLoader
类。接下来,我们通过一段代码来了解下一个Java程序需要用到几种类加载器。
public class MyClass {
public static void main(String[] args) {
// 获取当前类的类加载器
ClassLoader classLoader = MyClass.class.getClassLoader();
System.out.println(classLoader);
// 遍历当前类的父加载器
while (classLoader != null) {
classLoader = classLoader.getParent();
System.out.println(classLoader);
}
System.out.println("===========================");
// 获取系统类加载器加载的路径
System.out.println(System.getProperty("java.class.path"));
}
}
打印结果如下:
sun.misc.Launcher A p p C l a s s L o a d e r @ 18 b 4 a a c 2 s u n . m i s c . L a u n c h e r AppClassLoader@18b4aac2 sun.misc.Launcher AppClassLoader@18b4aac2sun.misc.LauncherExtClassLoader@42a57993
null
===========================
E:\Environment\java\jdk1.8\jre\jre\lib\charsets.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\ext\access-bridge-64.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\ext\cldrdata.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\ext\dnsns.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\ext\jaccess.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\ext\localedata.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\ext\nashorn.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\ext\sunec.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\ext\sunjce_provider.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\ext\sunmscapi.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\ext\sunpkcs11.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\ext\zipfs.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\jce.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\jsse.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\management-agent.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\resources.jar;
E:\Environment\java\jdk1.8\jre\jre\lib\rt.jar;
E:\ComProject\TestProject\lib\build\classes\java\main;
E:\Environment\java\jdk1.8\lib\idea_rt.jar
从打印的结果可知,MyClass类的类加载器为AppClassLoader
,它的父加载器为ExtClassLoader
,而ExtClassLoader
的父加载器为BootstrapClassLoader
。这里之所以讲ExtClassLoader的父加载器打印为null,那是因为BootStrapClassLoader由C/C++编写,并不是一个Java类,因此无法在java的代码中获取它的引用。
1.1.1.2 Android中的ClassLoader
Java中的ClassLoader加载的是jar文件
和.class字节码文件
,而Android虚拟机加载的是.dex字节码文件
,因此Java中的ClassLoader是不能适用在Android中。与Java中的ClassLoader一样,Android中的ClassLoader也分为系统类加载器和自定义类加载器,其中系统类加载器主要包括三种,即BootClassLoader
、PathClassLoader
和DexClassLoader
,需要注意的是,这三种系统类加载器均由Java实现,且它们的父类均为java.lang.ClassLoader
类,它们的继承关系(注:这里是父类与子类之间的继承
)如下:
接下来,我们重点分析下以下三种系统类加载器:
- BootClassLoader
BootClassLoader由Java实现,它继承于ClassLoader且是该类的内部类,是Android平台上所有ClassLoader的最终parent,其作用是是预加载常用类,比如Frament、Dialog、DownLoadManager等等。BootClassLoader预加载常用类的过程是在Android系统启动时完成的,具体来说是在Zygote进程启动过程中在ZygoteInit的main方法中被创建使用的。BootClassLoader的源码如下:
// Android8.0\libcore\ojluni\src\main\java\java\lang\ClassLoader$BootClassLoader
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);
}
// 根据指定类全路径名创建其Class对象
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
return Class.classForName(name, false, null);
}
...
}
- PathClassLoader
PathClassLoader继承于ClassLoader的实现类BaseDexClassLoader,它的作用为加载系统类和应用程序的类,它在SystemServer进程启动时被创建。由于PathClassLoader的构造方法中没有optimizedDirectory参数,因此不支持自定义解压dex文件存储路径,也就意味着PathClassLoader只能用于加载已经安装的apk的dex文件,这个dex文件在APK安装时会被存储到/data/dalvik-cache
目录下,也就是说PathClassLoader只能加载/data/dalvik-cache
目录中的dex文件。PathClassLoader源码如下:
// Android8.0\libcore\dalvik\src\main\java\dalvik\system\PathClassLoader.java
public class PathClassLoader extends BaseDexClassLoader {
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
public PathClassLoader(String dexPath, String librarySearchPath,
ClassLoader parent) {
// optimizedDirectory默认为/data/dalvik-cache