类加载子系统
代码编译的结果从本地机器指令码转化为字节码,是存储格式发展的一小步,但却是编程语言发展的一大步
—— 《深入理解JVM虚拟机》周志明·著
Java虚拟机将描述类的数据从class字节码文件加载到内存,并且对数据进行校验,转化,解析,初始化的工作,最终形成在内存中可以直接使用的数据类型。
这个过程叫做虚拟机的类加载机制。
图示
作用
-
类加载子系统负责从文件系统或者网络中加载Class文件(Class文件在开头有特定标识)。
-
l类加载器(Class Loader)只负责class文件的加载,至于是否可以运行,由执行引擎(Execution Engine)决定。
-
加载的类信息存放于一块成为方法区的内存空间。除了类信息之外,方法区还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)
类加载器扮演的角色
-
Car.class存放于本地硬盘中,在运行的时候,JVM将Car.class文件加载到JVM中,被称为DNA元数据模板
存放在JVM的方法区中,之后根据元数据模板实例化出相应的对象。
-
在
.class
->JVM
->元数据模板
->实例对象
这个过程中,类加载器扮演者快递员的角色。
类加载的时机
关于类加载的时机,《Java虚拟机规范》中并没有明确规定。这点可以由虚拟机的具体实现决定。
但是类的初始化阶段,规范中明确规定当某个类没有进行初始化,只有以下6中情况才会触发其初始化过程。
- 遇到
new
,getStatic
,putStatic
,invokeStatic
,这四条字节码指令的时候,如果改类型没有进行初始化,则会触发其初始化。也就是如下情况
1.1. 遇到new
关键字进行创建对象的时候。
1.2. 读取或者设置一个类的静态字段的时候(必须被final修饰,也就是在编译器把结果放入常量池中)。
1.3. 调用一个类的静态方法的时候。 - 使用java.lang.reflect进行反射调用的时候。
- 当初始化某个类,发现其父类没有初始化的时候。
- 当虚拟机启动的时候,会触发其主方法所在的类进行初始化。
- 当使用JDK1.7中的动态语言支持时,如果一个
java.lang.invoke.MethidHandle
实例最后的解析结果为REF_getStatic
,REF_putStatic
,REF_invokeStatic
,REF_newInvokeSpecial
四种类型的方法句柄,并且这个句柄对应的类没有被初始化。 - 当一个接口实现了JDK1.8中的默认方法的时候,如果这个接口的实现类被初始化,则该接口要在其之前进行实例化。
对于以上6中触发类的初始化条件,在JVM规范中有一个很强制的词,if and only if
(有且只有)。这六种行为被称为对类进行主动引用
,除此之外,其他引用类的方式均不会触发类的初始化。