Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、解析和初始化,最终造成能够被虚拟机直接使用的Java类型,这个过程被称做虚拟机的类加载机制。 ——《深刻理解Java虚拟机》html
加载、链接(验证、准备、解析)、初始化、使用、卸载。 java
这五个阶段的顺序是肯定的,类加载必须按照这种顺序“开始”(这些阶段一般是交叉混合进行的,因此执行顺序与完成顺序可能并非按照开始顺序)。web
《Java虚拟机规范》中并无进行强制约束,可是对于初始化阶段,则是严格规定了有且只有六种状况必须当即对类进行“初始化”(而加载、验证、准备天然须要在此之 前开始):缓存
接口初始化与类初始化不一样,只要是体如今上述第3点,当一个接口在初始化时,并不要求其父接口所有都完成了初始化,只有在真正使用到父接口的时候(如引用接口中定义的常量)才会初始化。安全
在加载阶段,Java虚拟机须要完成如下三件事情:数据结构
总结一下,就是读取Class文件,将类结构存到方法区,再在堆内建立一个Class对象。oracle
验证是链接阶段的第一步,这一阶段的目的是确保Class文件的字节流中包含的信息符合《Java虚 拟机规范》的所有约束要求,保证这些信息被看成代码运行后不会危害虚拟机自身的安全。jvm
准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初始值的阶段。编辑器
🌰1
//对于static变量来讲,在准备阶段结束以后,value的值是0,而非123,等到初始化时才会设置成123。 public static int value = 123; 🌰2 //而对于常量来讲,在准备阶段就会被设置成123。 public final static int value = 123; 复制代码
解析阶段是Java虚拟机将常量池内的符号引用替换为直接引用的过程。url
符号引用就是字符串,这个字符串包含足够的信息,以供实际使用时能够找到相应的位置。你好比说某个方法的符号引用,如:“java/io/PrintStream.println:(Ljava/lang/String;)V”。里面有类的信息,方法名,方法参数等信息。
关于符号引用能够看看R大的回答。JVM里的符号引用如何存储?
还有《Java虚拟机规范》第四章class文件格式的第四节常量池 有介绍符号引用的格式。
初始化阶段就是执行类构造器clinit()方法的过程。
clinit()方法是由编译器自动收集类中的全部类变量的赋值动做和静态语句块(static{}块)中的语句合并产生的。就是static变量和static方法合并后的结果。
以下图,static的变量赋值和方法会被合并到static{}(javap反编译的结果,static{}就是clinit())里。
当AppClassLoader加载一个class时,它首先不会本身去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader
去完成。
当ExtClassLoader加载一个class时,它首先也不会本身去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader
去完成。
若是BootStrapClassLoader
加载失败(例如在$JAVA_HOME/jre/lib
里未查找到该class),会使用ExtClassLoader
来尝试加载;
若ExtClassLoader
也加载失败,则会使用AppClassLoader
来加载,若是AppClassLoader
也加载失败,则会报出异常ClassNotFoundException
。
防止重复加载,防止核心库被修改。
使同名类(🌰java.lang.Object)在程序的各类类加载器环境中都可以保证是同一个类。
《深刻理解Java虚拟机》《Java虚拟机规范》
图片来源《深刻理解Java虚拟机》
本文使用 mdnice 排版