摘自《深入理解Java虚拟机》第二版
Java从代码到最终执行,一般需要两个过程:
编译:把Java文件通过javac命令变异成字节码,也就是.class文件。
运行:把编译好的.class文件交给JVM运行。
这里说的类加载过程指的是JVM把.class文件中类信息加载进内存,并进行解析生成对应的class对象的过程。
类加载过程主要分为三部分:
具体来说就是加载、验证、准备、解析、初始化五个阶段。
“加载”是“类加载”过程的一个阶段。简单来说加载就是把class字节码文件从各个来源通过类加载器装入内存中。
保证加载进来的字节流符合虚拟机规范,不会造成安全错误。
主要是为类变量(静态变量)分配内存,并且赋初值(这里的初值指的是JVM根据变量类型的默认初始值,不是代码中的初始值)。
如:8中基本类型的初始为0,引用类型的初值为null,注意:常量的初值即为代码中设置的值如final static temp= 22, 那么该阶段temp的初值就是22。
将常量池内的符号引用替换为直接引用的过程。
例如:调用方法test(),方法地址为2222,test就是符号引用,2222就是直接引用。
这个阶段主要是对类变量初始化,是执行类构造器的过程。
换句话说,只对static修饰的变量或语句进行初始化。
如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。
如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。
启动类加载器(bootstrap class loader):用来加载Java的核心库,用原生代码实现(c++)。
扩展类加载器(extensions class loader):加载Java的扩展库。
应用程序加载器/系统类加载器(system class loader):它根据Java应用的类路径(classpath)来加载类。
自定义类加载器:自己定义的类加载器。
说到类加载器那么就要谈谈类加载器之间的关系,加载器之间的关系称作为双亲委派模型(除了bootstrap ClassLoader外,其他的类加载器都有自己的父类加载器,类加载器都是使用组合关系来复用父类加载器的代码)
双亲委派模型工作过程:如果一个类加载器收到了类加载的请求,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每个层次的类加载器都是这样的,因此所有的加载器请求最终都应该传送到顶层的启动类加载器,之后当父类加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己去加载。