首先一个java文件从编码完成到最终执行,是经历两个过程的,编译和运行,编译就是把java文件通过javac编译成字节码,也就是.class文件,运行就是把.class文件交给JVM执行。
然后类加载过程就是说虚拟机将.class文件中的类信息加载到内存,然后解析生成对应的class对象的过程。这过程再细分的流程是:加载--链接(验证、准备、解析)--初始化。虚拟机不是一次性把所有类加载到内存中,而是第一次需要运行时才会进行加载,且只会进行一次。
1.加载:
①通过类的完全限定名来获取该类的二进制字节流。
②将这个流中的静态存储结构转变为方法区的运行时数据结构;(我的理解是说在这个时期就已经为该类的静态成员或方法在方法区生成相应的结构)
③在java堆里生成相应的java.lang.Class的对象,它封装了方法区内的数据结构,目的是提供程序访问方法区数据时的结构。
2.链接(又包括 验证、准备、解析) :
①验证: 这一步的意义是为了确保字节流文件中的信息符合当前虚拟机的要求,且不会对虚拟机造成损害。(需要知道的是.class文件可能不是通过Java源码编译而来的,有可能是直接由16进制编辑器编辑,或者有了损坏等,所以说如果不进行字节流的检查等,可能因为载入了有害的字节流而导致系统的崩溃,这一步主要就是一种自我保护机制)。
验证的具体内容包括:文件格式验证、元数据验证、字节码验证、符号引用验证。
文件格式验证:这一阶段主要是验证字节流文件是否符合class文件的规范,是否可以被当前版本的虚拟机处理。也就是说只有进行了这一阶段之后这个字节流文件才能够正确的解析存储到方法区。
元数据验证:主要是对元数据进行语义检验,验证是否符合java里的元数据标准。
字节码验证:它是验证阶段中最复杂的一步,因为他要通过控制流和数据流分析来确定程序的语义是否符合逻辑,是否是合法的。
符号引用验证:可以看做是对类以外的信息进行匹配性校验的过程,在符号引用会转化为直接引用,这个转化动作会在解析阶段发生。所以连接阶段是和其他阶段交替进行的。
②准备:为类变量分配内存空间并设定初始值。这里需要注意的是初值是说(0,null之类的),还有就是static final是可以做到直接给值的。
③解析:将常量池中的符号引用转换为直接引用的过程。包括:类或接口的解析、字段解析、类方法解析、接口方法解析。
3.初始化:这是类加载的最后一步,可以说这是真正的开始执行java代码了,之前准备阶段已经赋了初值,而这个阶段则是按程序员主观安排的计划去初始化值(需要注意的是这个阶段针对的也是类变量也就是说它是clinit)。