Java虚拟机经过装载、链接和初始化一个Java类型,使该类型能够被正在运行的Java程序所使用。其中装载就是把二进制形式的Java class文件读入Java虚拟机中去;链接把读入虚拟机的二进制形式的Java class文件合并到虚拟机的运行时的状态中去。链接能够分为三个子步骤,验证,准备和初始化。验证步骤确保了Java类型数据格式正确而且适于Java虚拟机使用。准备为该类型分配内存(如为类变量分配内存)。解析负责将常量池中的符合引用转换为直接引用,虚拟机的实现能够推迟解析这一步骤。即当运行中的程序真正使用某个符号的时候再去解析它。(符号引用变为直接引用)。初始化为类变量赋以适当的初始值。
下面就这5个步骤进行详细的解析:java
装载阶段由三个动做完成程序员
装载的最终目的就是建立java.lang.class的实例对象,解析二进制数据流为方法区的内部数据结构,并在堆上面创建一个Class对象。Class对象是Java程序与内部数据结构之间的接口。数据库
Java类型要么被启动类装载器装载,要么被用户自定义的类加载器加载。
类加载器并非在某个类型首次主动使用的时候加载它。能够提早预判,预加载这个类型。若是预加载的时候出现问题,不会当即报错。直到程序主动使用该类才报错。也就是说程序已知不主动使用该类类型,类加载器就一直不报错。网络
装载时会作两项检查,虽然在验证阶段以前进行,但逻辑上属于验证阶段。数据结构
类型被加载后,虚拟机开始链接,链接第一步是验证,即确认它是否符合Java语言的语义,而且不会危及虚拟机的完整性。
验证的时机和方式,不一样虚拟机有着不一样的实现。虚拟机规范只是规定了虚拟机在验证过程当中能够抛出的异常以及在何种状况下必须抛出它们。
验证阶段每每会验证以下内容:性能
上述任务最复杂的是最后一个,检查字节码的完整性。不能由于挑战指令超出了方法末尾致使了虚拟机崩溃。虚拟机必须在验证阶段检查出这样的字节码是非法的,从而抛出一个错误。
不过虚拟机规范并未规定字节码验证必须在验证阶段执行,也能够在执行每条语句的时候单独进行验证。Java虚拟机指令集当初设定目标是字节码流一次性使用数据流分析器进行验证。不过运行时候进行验证,会使得Java程序运行速度提升。当使用数据流分析器进行字节码验证时候,可能为了确保符合Java语言的语义而装载其余的类。好比加载了Float类,必须还加载其父类Number保证其不是一个final类。.net
验证阶段以后可能还会进行一项检查,那就是符号引用的验证。虚拟机在将符号引用替换为直接引用,须要检查该元素的存在性以及访问的权限。逻辑上属于验证,但每每在解析阶段发生。指针
在准备阶段,Java虚拟机为类变量分配内存,并设置默认的初始值。在正式初始化阶段以前,类变量都没有被正式初始化为真正的初始值。
准备阶段,干的另一件事就是可能为一些数据结构分配内存,进而提升程序运行的性能。好比方法表的创建,它包含了指向类中每个方法包括从超类继承方法的指针。从而能够在执行继承方法时候不须要搜索超类。对象
解析过程就是在类型的常量池中寻找类、接口、自动和方法的符合引用,把这些符号引用变成直接引用的过程。还记得逻辑上属于验证的符合引用的验证么?解析何时执行是虚拟机本身决定的,能够在初始化阶段后面执行。blog
初始化阶段为类变量赋予正确的初始值。在准备阶段,类变量被赋予了默认值,在这一阶段,类变量被赋予正确的初始值,即程序员但愿这个类变量具有的起始值。
具体的初始化过程参见下一篇博客《浅谈类加载的初始化阶段》