类加载一般认为是由加载、连接、初始化三个部分。
其中连接又可以细分为验证、准备、解析三个阶段。
类加载的全过程分别是:加载、验证、准备、解析和初始化 5 个阶段动作。
注意,这些阶段并不是按部就班,一般都是交叉混合。
“加载”是“类加载”过程的一个阶段。注意区分两者。加载阶段,JVM 需要做以下三件事:
1) 通过一个类的全限定名来获取定义此类的二进制字节流。
2) 将这个字节流所代表的静态存储结构转化为方法去的运行时数据结构。
3) 在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口。
通过一个类的全限定名来获取定义此类的二进制字节流,这一条并没有明确规定从哪里获取,因此方式有很多种:
1) Class 文件
2) ZIP 包,如 JAR、EAR、WAR、
3) 网络,典型场景就是 Applet
4) 运行时计算,典型的是动态代理
5) 其他文件生成,如 JSP
6) 数据库读取
加载阶段与连接阶段的部分内容(如一部分字节码文件格式验证动作)是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始。
2011 年发布的《Java 虚拟机规范(Java SE 7 版)》,大幅增加了描述验证过程的篇幅(从不到10页增加到130页)。
如果运行的全部代码(包括自己编写的以及第三方包中的代码)都已经被反复使用和验证过,那么在实施阶段就可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。
准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区进行分配。
* 这时候进行内存分配的仅包括类变量(被 static 修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在 Java 堆中。
* 其次,这里所说的初始值是数据类型的零值,假设有如下定义:
public static int value = 123;那么变量 value 在准备阶段过后的初始值为 0 而不是 123.