浅谈Java类型装载、链接与初始化--转自https://blog.csdn.net/lincolnmi/article/details/50538016

类型装载、链接与初始化

Java虚拟机经过装载、链接和初始化一个Java类型,使该类型能够被正在运行的Java程序所使用。其中装载就是把二进制形式的Java class文件读入Java虚拟机中去;链接把读入虚拟机的二进制形式的Java class文件合并到虚拟机的运行时的状态中去。链接能够分为三个子步骤,验证,准备和初始化。验证步骤确保了Java类型数据格式正确而且适于Java虚拟机使用。准备为该类型分配内存(如为类变量分配内存)。解析负责将常量池中的符合引用转换为直接引用,虚拟机的实现能够推迟解析这一步骤。即当运行中的程序真正使用某个符号的时候再去解析它。(符号引用变为直接引用)。初始化为类变量赋以适当的初始值。 
下面就这5个步骤进行详细的解析:java

装载

装载阶段由三个动做完成程序员

  1. 经过该类型的彻底限定名,产生一个表明该类型的二进制数据流。 
    该二进制数据流能够遵循class文件格式,也能够遵照其余数据格式。全部虚拟机必须能识别Java class文件格式,可是个别的也能够识别其余二进制格式。 
    Java虚拟机并未规定该二进制数据流如何产生,所以下面列出了可能产生二进制数据的方式: 
    从本地文件系统装载class文件; 
    从网络下载一个class文件; 
    从ZIP,JAR,CAB中提取class文件; 
    从专有数据库中提取class文件; 
    将Java源文件编译为class文件; 
    使用上述方法,可是产生非class文件格式的二进制文件格式
  2. 解析这个二进制数据流为方法区的内部数据结构。
  3. 建立一个表示该类型的java.lang.class类的实例。

装载的最终目的就是建立java.lang.class的实例对象,解析二进制数据流为方法区的内部数据结构,并在堆上面创建一个Class对象。Class对象是Java程序与内部数据结构之间的接口。数据库

Java类型要么被启动类装载器装载,要么被用户自定义的类加载器加载。 
类加载器并非在某个类型首次主动使用的时候加载它。能够提早预判,预加载这个类型。若是预加载的时候出现问题,不会当即报错。直到程序主动使用该类才报错。也就是说程序已知不主动使用该类类型,类加载器就一直不报错。网络

装载时会作两项检查,虽然在验证阶段以前进行,但逻辑上属于验证阶段。数据结构

  1. 验证class文件格式是否正确,如魔数,每一个部分在正确位置,正确的长度,文件的长度不是太长或过短等。 保证正式解析二进制class文件时候,不会形成虚拟机的崩溃。
  2. 确保每一个除Object以外每一个类都有一个超类,加载某个类的时候,确保该类的全部超类必须加载。

验证

类型被加载后,虚拟机开始链接,链接第一步是验证,即确认它是否符合Java语言的语义,而且不会危及虚拟机的完整性。 
验证的时机和方式,不一样虚拟机有着不一样的实现。虚拟机规范只是规定了虚拟机在验证过程当中能够抛出的异常以及在何种状况下必须抛出它们。 
验证阶段每每会验证以下内容:性能

  1. 检查final的类不拥有子类
  2. 检查final方法不能被覆盖
  3. 确保类型和超类型之间没有不兼容的方法申明(好比两个方法签名彻底同样,但返回类型不一样)
  4. 检查全部的常量池入口相互之间保持一致(好比CONSTANT_String_info入口的string_index项目必须是一个CONSTANT_Utf8_info入口的索引)
  5. 检查常量池中全部的特殊字符串(类名,字段名,方法名,字段描述符和方法描述符)是否符合格式
  6. 检查字节码的完整性

上述任务最复杂的是最后一个,检查字节码的完整性。不能由于挑战指令超出了方法末尾致使了虚拟机崩溃。虚拟机必须在验证阶段检查出这样的字节码是非法的,从而抛出一个错误。 
不过虚拟机规范并未规定字节码验证必须在验证阶段执行,也能够在执行每条语句的时候单独进行验证。Java虚拟机指令集当初设定目标是字节码流一次性使用数据流分析器进行验证。不过运行时候进行验证,会使得Java程序运行速度提升。当使用数据流分析器进行字节码验证时候,可能为了确保符合Java语言的语义而装载其余的类。好比加载了Float类,必须还加载其父类Number保证其不是一个final类。.net

验证阶段以后可能还会进行一项检查,那就是符号引用的验证。虚拟机在将符号引用替换为直接引用,须要检查该元素的存在性以及访问的权限。逻辑上属于验证,但每每在解析阶段发生。指针

准备

在准备阶段,Java虚拟机为类变量分配内存,并设置默认的初始值。在正式初始化阶段以前,类变量都没有被正式初始化为真正的初始值。 
准备阶段,干的另一件事就是可能为一些数据结构分配内存,进而提升程序运行的性能。好比方法表的创建,它包含了指向类中每个方法包括从超类继承方法的指针。从而能够在执行继承方法时候不须要搜索超类。对象

解析

解析过程就是在类型的常量池中寻找类、接口、自动和方法的符合引用,把这些符号引用变成直接引用的过程。还记得逻辑上属于验证的符合引用的验证么?解析何时执行是虚拟机本身决定的,能够在初始化阶段后面执行。blog

初始化

初始化阶段为类变量赋予正确的初始值。在准备阶段,类变量被赋予了默认值,在这一阶段,类变量被赋予正确的初始值,即程序员但愿这个类变量具有的起始值。 
具体的初始化过程参见下一篇博客《浅谈类加载的初始化阶段

相关文章
相关标签/搜索