JVM的类加载阶段
如图所示:JVM的类加载阶段分为5个阶段,加载,验证,准备,解析,初始化。初始化完成后就能够使用该类,同时在该类不再被需要时,可以从JVM中卸载它。
每个阶段的作用
加载:简单的说就是JVM读取Class文件,并且根据Class文件信息创建java.lang.Class对象。
验证:这个阶段主要是验证Class文件的字节流是否符合虚拟机的要求规范,从而保障虚拟机的安全,通过这步的Class文件才能被JVM加载。
准备:这个阶段主要是在方法区中为类变量分配需要的内存空间同时设置类中变量的初始值。不过final类型的变量和非final类型的变量在准备阶段的数据初始化过程是不一样的。
没有final修饰符的变量,如下:
public static int i=100;
一般来说,基础数据类型的初始值默认是0,所以静态变量i在准备阶段的值默认是0,而将他变成100的操作是在初始化阶段完成的。
如果加上了final修饰符:
public static final int i=100;
那么i在准备阶段是就会被赋值为100,因为final修饰的变量会直接被作为常量处理,直接赋值原始值。
解析:JVM将常量池中的符号引用替换为直接引用
初始化:通过执行类构造器的< client >方法为类进行初始化。而< client >方法是在编译阶段由编译器自动收集类中静态语句块以及变量的赋值操作组成的。在子类的< client >方法执行前,必须保证父类的< client >方法已经执行成功了。
那么何时需要对类进行初始化呢?
有且只有以下几种情况必须对类进行初始化:
- 使用了new关键字实例化对象时
- 读取或者设置静态变量时,不过final修饰的静态变量除外,因为它在准备阶段就持有原始值了
- 调用了类的静态方法时
- 使用反射时,如果类没有初始化,那么就会进行初始化
- 在初始化一个类时,需要先初始化其父类
- 被标明为启动类的类(包含了main()方法的类)要初始化
- JDK1.7后,使用动态语言支持时,如果一个java.invoke.MethodHandle实例最后结果要执行以上1,2,3三种情况,也是需要初始化的