1.类加载机制
.java文件不是可执行的文件,需要先编译成.class文件才可以被虚拟机执行。而类加载就是指通过类加载器把.class文件加载到虚拟机的内存空间,具体来说是方法区。类通常是按需加载,即第一次使用该类时才加载。
Java与Android都是把类加载到虚拟机内存中,然后由虚拟机转换成设备可识别的机器码。由于它们使用的虚拟机不同,所以在类加载方面也有所区别。Java的虚拟机是JVM,Android的虚拟机是dalvik/art(5.0以后虚拟机是art,是对dalvik的升级)。Java虚拟机运行的是class文件,而Android 虚拟机运行的是dex文件。dex其实是class文件的集合,是对class文件优化的产物,为了避免出现重复的class。
先了解一下Android的运行流程:
①Android程序编译的时候,会将.java文件编译成.class文件;
②生成apk时,将.class文件打包为.dex文件;
③Android程序运行的时候,Android的Dalvik/art虚拟机就加载dex文件,然后加载其中的.class文件到内存中来使用。
当需要使用某个类时,虚拟机就会加载它的Class文件,并创建对应的Class对象。将Class文件加载到虚拟机的内存里,这个过程称为类加载。
类加载流程:
一个类被加载到虚拟机内存中需要经历加载、连接、初始化几个过程。其中连接分为三个步骤:验证、准备、解析。
①步骤一:加载:将外部的Class文件加载到虚拟机内,并存储到方法区。
加载过程主要做了三件事:
1)通过类的全限定名来获取定义此类的二进制字节流。即把类以流的形式加载进内存,类的来源没有说,可以是jar包,也可以是class文件或者是apk文件。这个特性是能够实现插件化技术的理论基础。
2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。在获取到这个字节流以后,虚拟机就会把类中的静态存储结果保存到方法区中,保存的过程会转化对应方法区中的数据结构。所以说静态的结构都保存在内存中的方法区中。
3)在内存中生成一个代表这个类的java.lang.Class对象,作为这个类的各种数据的方位入口。当类加载进内存以后,每个类都会生成一个对应的Class对象,当使用这个类的时候,都是通过此Class对象为入口来使用的,比如写程序的时候通过new关键字创建一个类的对象就是通过这个类的Class对象来创建的。
②步骤二:验证:确保加载到Class文件里的信息符合虚拟机要求。主要是对类中的语法结构是否合法进行验证,确认类型符合Java语言的语义。
③步骤三:准备:为类变量分配内存,并设置类变量的初始化值(初始值通常为0,非开发者定义的值)。这个阶段是给类中的类变量分配内存,设置默认初始值,比如一个静态的int变量初始值是0,布尔变量初始值是false。
④步骤四:解析:将常量池内的符号引用转为直接引用,如hello()方法,hello是符号引用,地址值是直接引用。也就是在类型的常量池中寻找类、接口、字段和方法的符号引用,把这些符号引用替换成直接引用的过程。这个过程可以理解为一开始虚拟机对加载到内存中的各种类、字段等并没有一一编号,只是通过一个符号去表示,在解析阶段,虚拟机把内存中的类、方法等进行统一管理起来。
⑤步骤五:初始化:对类变量进行初始化。初始化阶段才真正到了类中定义的java代码的阶段,在这个阶段会对类中的变量和一些代码块进行初始化,比如为类变量进行初始化,在准备阶段对类变量进行的默认初始化,到这个阶段就对变量进行显式的赋值,其中静态代码块就是在这个阶段来执行的。
注意:初始化不会马上执行,当一个类被主动使用的时候才会去初始化,主要有几种情况:
1)当创建某个类的新实例时(如通过new或者反射等);
2)当调用某个类的静态方法时;
3)当使用某个类或接口的静态字段时;
4)当调用Java API中的某些反射方法时,比如类Class中的方法,或者java.lang.reflect中的类的方法时;
5)当初始化某个子类时;
类从被加载到虚拟机内存到被卸载,整个完整的生命周期包括:加载 --> 验证 --> 准备 --> 解析 --> 初始化 --> 使用 --> 卸载七个阶段,其中验证、准备、解析这三个部分统称为连接。
类加载流程比较复杂,但是开发者能够控制的只有第一步「加载」还有最后一步「初始化」,第一步记载的理论基础决定了插件化可以实现,最后一步初始化就是执行实际程序中的代码。其余都是由虚拟机控制的。
类加载的主要作用:
①实现类的加载功能
②确保被加载类在虚拟机中的唯一性
2.Android中的类加载器
由于java编译出来的是class文件,而Android的APK中包含的是dex文件,dex文件是将所需的所有class文件重新打包,打包的规则不是简单地压缩,而是完全对class文件内部的各种函数表、变量表等进行优化,并产生一个新的文件,所以java和Android中的ClassLoader也不一样,这里主要来看一下Android中的ClassLoader。
类加载进内存后,Android程序通过ClassLoader类去加载内存中的类,然后进行解析运行。
Android中包含以下几种类加载器:
①BootCla