关于java类加载:
类从被加载到虚拟机内存开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸载(unLoading)七个阶段。其中验证、准备、解析三个部分统称为连接(Linking)
加载、验证、准备、初始化、卸载这五个顺序是固定的,而解析阶段则不一定,在某些情况下可以在初始化阶段之后再开始,这是为了支持java语言的运行时绑定。、
加载过程:
- 加载
在加载阶段,虚拟机需要完成以下三件事情:
1.通过一个类的全限定名来获取定义此类的二进制流
2.将这个字节流多代表的静态存储结构转化为方法区的运行时数据结构
3.在java堆中生成一个代表这个类的class对象,作为方法区这些数据的访问入口 - 验证
验证是连接阶段的第一步,这一阶段的目的是为了确保class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全(因为将java编译成class文件的方式有很多种),不同的虚拟机对类型的验证的实现可能有所不同,但大致上都会完成以下四个阶段的校验过程:
1.文件格式验证
该验证阶段的主要目的是保证输入的字节流能正确的解析并保存于方法区之内,格式上符合描述一个java类型信息的要求
2.元数据验证
该验证阶段的主要目的是对类的元数据信息进行语义校验,保证不存在不符合java语言规则的元数据信息
3.字节码校验
该阶段是整个验证过程中最复杂的一个阶段,主要是进行数据流和控制流的分析,主要在元数据校验以后对类的方法体进行校验。主要是用来保证被校验的类在运行时不会危害虚拟机的安全
4.符号引用验证
符号引用验证的目的是确保解析动作能正常执行,是对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验 - 准备
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配,这个阶段有两个容易产生混淆的概念需要强调一下,首先是这个时候进行内存分配的金包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在实例化的时候随着对象一起分配到java堆中,其次是这里所说的初始值“通常情况”下是数据类型的零值 解析
解析阶段是虚拟机将常量池中的符号引用替换为直接引用的过程
符号引用:
符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用于虚拟机实现的内存布局无关,引用的目标不一定已经加载到内存中。
直接引用:
直接引用可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用是与虚拟机实现的内部布局相关的,同一个符号引用在不同的虚拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经在内存中存在。初始化
类初始化阶段是类加载过程的最后一步,前面的类加载过程中,除了在加载阶段用户应用程序可以通过自定义类加载器参与之外,其余动作完全由虚拟机主导和控制,在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则是根据程序员通过程序制定的主观计划去初始化类变量和其他资源,也就是平常我们说的执行类的构造器。