JVM类加载机制
类加载机制概述:虚拟机把描述类的数据从Class文件加载到内存,并对数据 进行校验、解析、和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制
类的生命周期:7个阶段
其中,验证——准备——解析 称为连接阶段。除了解析外,其他阶段是顺序发生的,而解析可以与这些阶段交叉进行,因为Java支持动态绑定(晚期绑定),需要运行时才能确定具体类型。

其中,验证——准备——解析 称为连接阶段。除了解析外,其他阶段是顺序发生的,而解析可以与这些阶段交叉进行,因为Java支持动态绑定(晚期绑定),需要运行时才能确定具体类型。

在类的加载阶段,加载、验证、准备、初始化是按照顺序严格执行的。但是 Java 虚拟机规范并没有规定什么情况下执行类加载的第一个阶段:加载,这一点可以交给虚拟机的具体实现自由把握。
可以但是对于初始化阶段,虚拟机规范严格规定: 有且只有 5 种情况 必须立即对类进行初始化(加载、验证、准备自然需要在之前执行),上图已有说明,此处重复介绍:
(2)使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行初始化,则需要先触发其初始化。
(3)当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
(4)当虚拟机启动的时候,用户需要指定一个需要执行的主类(包含 main 方法的那个类),虚拟机会先初始化这个类。
(5)当使用 JDK 1.7 的动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果 REF_getStatic、REF_putStatic、REF_invokeStatic 的方法句柄,并且这个方法句柄对应的类没有进行过初始化,则需要先触发其初始化。
下面通过一个例子来初步了解下类的加载过程,单例模式中有一个方式是静态内部类来实例化单例,是懒汉式单例(基于双重检查锁和volatile )的变种。
代码:
public class Singleton { private Singleton (){ System.out.println("外部类实例化"); } static { System.out.println("外部类加载"); } private static class SingletonHolder { static { System.out.println("静态内部类加载"); } private static final Singleton INSTANCE = new Singleton(); } public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } public static void main(String[] args) { System.out.println("main方法执行"); Singleton instance = Singleton.getInstance(); } }
结果:
根据上面的结果,产生了两个疑问
1.为什么外部类静态代码块先执行才执行main方法?
2.为什么调用Singleton.getInstance()才触发Singleton的实例化?
问题1答案: 当虚拟机启动的时候,用户需要指定一个需要执行的主类(包含 main 方法的那个类),虚拟机会先初始化这个类。初始化阶段类的静态变量赋初始值和执行静态代码块static{ }中的内容,执行的先后顺序取决于在源文件中出现的顺序。
问题2答案: 触发getstatic后,即访问该类的静态成员变量,这个时候才触发了 Singleton 类的初始化。
=========================================================================================================================================
我只是一粒简单的石子,未曾想掀起惊涛骇浪,也不愿随波逐流
每个人都很渺小,努力做自己,不虚度光阴,做真实的自己,无论是否到达目标点,既然选择了出发,便勇往直前
我不能保证所有的东西都是对的,但都是能力范围内的深思熟虑和反复斟酌

浙公网安备 33010602011771号