二、虚拟机执行子系统(2)
二、虚拟机类加载机制
1、概述
虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。
类的加载和连接过程都是在运行期间完成的,java的动态扩展语言特性就是依赖这样的特性实现的。
类的加载过程可以被分成:加载、验证、准备、解析、初始化、使用和卸载这七个阶段。其中,加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的。
2、加载时机
对于初始化阶段,虚拟机规定有且只有四种情况必须立即对类进行初始化:
1>new关键字实例化对象、读取或设置一个类的静态字段(除了被final修饰、已在编译期把结果放入常量池的静态字段)、调用一个类的静态方法的时候
2>使用java.lang.reflect包的方法对类进行发射调用的时候
3>初始化一个类的时候,发现其父类还没有进行初始化,就先触发其父类的初始化
4>虚拟机启动时,用户需要制定一个要执行的主类,虚拟机会先初始化这个类
3、类加载的过程
3.1加载
1>通过类的权限定名来获取定义此类的二进制字节流
2>将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3>在java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口
3.2验证
1>文件格式验证
2>元数据验证
3>字节码验证
4>符号引用验证
3.3准备
正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。
类变量的初始值会被设置成默认值,只有被final修饰的类变量才会被设置成字面量。
3.4解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。
直接引用:直接引用可以是直接指向目标的指针、相对偏移量或是一个能简介定位到目标的句柄。
3.5初始化
初始化阶段是执行类构造器<clinit>()方法的过程。也就是按照字节码文件进行程序初始化。
<clinit>()方法:由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{})中的语句合并产生。
三、类加载器
1、概述
对于任何一个类,需要由加载它的类加载器和它本身来确定其唯一性。
相等:Class对象的equals()、isAssignableFrom()、isInstance(),以及instanceof关键字做对象所属关系判定等结果都为true
2、双亲委派模型
双亲委派模型要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器。这里类加载器之间的斧子关系一般不会以继承的关系来实现,而是都是用组合关系来服用父加载器的代码。
工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。