这一节咱们来总结一下JVM类加载机制。具体目录以下:
java
虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终造成能够被虚拟机直接使用的Java类型,这就是Java虚拟机的类加载机制。程序员
在Java中,类型的加载、链接和初始化过程都在程序运行期间完成的,这种策略虽然会使类加载时增长一些性能开销,可是提供了高度的灵活性,Java里天生能够动态扩展的语言特就是依赖于运行期动态加载和动态链接的特色实现的。
Class文件指的是一串二进制的字节流。实际上,每一个Class文件都有可能表明着Java语言中的一个类或者接口。数组
在这七个过程当中,加载、验证、准备、初始化、卸载这5个阶段的顺序是必定的,类的加载过程必须按照这种顺序循序渐进地开始,而解析过程则不必定:它在某个状况下能够在初始化阶段以后再开始,这是为了支持Java语言语言的运行时绑定(也叫动态绑定和晚期绑定)。
这里强调的是:类加载阶段都是互相交叉地混合式进行的,一般是在一个阶段执行的过程当中调用、激活另外一阶段。安全
对类的初始化操做可分为主动引用和被动引用
主动引用:在如下5种状况下会进行类的主动引用的初始化操做:数据结构
值得注意的是:
接口也有本身的初始化过程:编译器会为接口生成“()”类构造器,用于初始化接口中所定义的成员变量。
接口和类初始化的区别:当一个类在初始化时,其父类都基本上初始化过了,然而接口在初始化的时候,只有真正用到父接口的时候(如引用接口中定义的常量)才会进行初始化。性能
在加载阶段,虚拟机须要完成如下3件事情:spa
非数组类的加载是可控性最强的。用户除了使用系统提供的引导类加载类来完成,也能够由用户自定义的类加载器去加载(重写一个类加载器的loadClass())。
注意:数组类自己不经过类加载器建立,它是由JVM直接建立的。但数组类和类加载器仍有很紧密的关系,由于数组类的元素类型最终是靠类加载器去建立。
加载完成后,虚拟机外部的二进制字节流就按照虚拟机所需格式存储在方法区之中,方法区中的数据存储格式由虚拟机实现自行定义。而后在内存中实例化一个java.lang.Class类的对象(能够在Java堆中,也能够在方法区中),该对象将做为程序去访问方法区中的这些类型数据的外部接口。
加载阶段与链接阶段的部份内容(如一部分字节码文件格式验证动做)是交叉进行的,加载阶段还没有结束,链接阶段就可能开始了。可是夹在加载阶段进行的动做,仍然属于链接阶段的内容。指针
验证是链接的第一步,目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,而且不会危及虚拟机自己的安全。
验证阶段的四个步骤:文件格式检验、元数据检验、字节码检验、符号引用检验。对象
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段。这些变量所使用的内存将在方法区中进行分配。此时进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一块儿分配在Java堆中。另外,在这里分配的静态类变量是将其值定义为0等默认值,而不是咱们定义的。由于这时还没有执行任何Java方法,咱们定义的赋值的putStatic指令是程序被编译后,存放在类构造器()方法中,因此正确的赋值将在初始化阶段执行。
若是类变量被final修饰,那么在这种状况下,在编译时Javac将会为该变量生成ConstantValue属性,在准备阶段虚拟机会根据该属性设置类变量的正确值。继承
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
a、符号引用:以一组符号来描述所引用的目标,符号能够是任何形式字面量,只要使用时无歧义地定位到目标就行。
b、 直接引用:直接引用是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。引用的目标已经在内存中存在。
虚拟机实现能够根据须要来判断到底在类被加载器加载时就对常量池中的符号引用进行解析,仍是等到一个符号引用将要被使用时才去解析它。解析动做主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。
类加载的最后一步,真正执行类中定义的Java程序代码(字节码)。 初始化阶段是执行类构造器()方法的过程,根据程序员经过程序制定的主观的计划去初始化类变量和其余资源。