JVM(一)类加载机制
1)Java文件先通过编译器变为.class文件
2)类加载器将.class文件加载到JVM。
类加载的过程简述:
Java文件先通过编译器变为.class文件
类加载器将.class文件加载到JVM。
一、JVM 组成和作用
1、 类装载器(Class Loader):.class文件由类加载器加载到数据运行区,
2、数据运行区 (Runtime data area):;
3、 执行引擎(Execution Engine):由于字节码只是JVM的指令集规范,不能交给底层操作系统执行,需要特定的命令解析器执行引擎翻译成底层系统指令,再交由CPU执行;
4、 本地库接口(Native Interface): 执行底层命令操作系统,需要调用其他语言的本地库接口来实现功能;
二、类装载的过程
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。它们的顺序如下图所示
1、加载
根据查找路径找到相应class文件导入;
2、检查
检查加载的class文件正确性;
3、准备:
给类中的静态变量分配内存空间;
类变量(static)会分配内存,但是实例变量不会,实例变量主要随着对象的实例化一块分配到java堆中;
这里的初始值指的是数据类型默认值,而不是代码中被显示赋予的值。比如
public static int value = 1; //在这里准备阶段过后的value值为0,而不是1。赋值为1的动作在初始化阶段。
注:准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。这时候进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在堆中。其次,这里所说的初始值“通常情况”下是数据类型的零值,假设一个类变量的定义为:
public static int value=123;
那变量value在准备阶段过后的初始值为0而不是123。因为这时候尚未开始执行任何java方法,而把value赋值为123的putstatic指令是程序被编译后,存放于类构造器()方法之中,所以把value赋值为123的动作将在初始化阶段才会执行。
至于“特殊情况”是指:public static final int value=123,即当类字段的字段标注为final之后,value的值在准备阶段初始化为123而非0.
总结:final是在准备阶段时就赋值了,static准备阶段时数据是零值,在初始化阶段才会赋值。(面试题)
4、解析
是虚拟机将常量池内的符号引用替换为直接引用的过程。解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。
5、初始化
类初始化阶段是类加载过程的最后一步,到了初始化阶段,才真正开始执行类中定义的java程序代码。
码文件被加载到内存后,先进行链接的验证这一步骤,验证通过后准备阶段,给a分配内存,因为变量a是static的,所以此时a等于int类型的默认初始值0,即a=0,然后到解析(后面在说),到初始化这一步骤时,才把a的真正的值10赋给a,此时a=10。
三、类的初始化时机
3.1、类什么时候才被初始化
- 创建类的实例,也就是new一个对象
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射(Class.forName("com.lyj.load"))
- 初始化一个类的子类(会首先初始化子类的父类)
- JVM启动时标明的启动类,即文件名和类名相同的那个类
3.2、类的初始化步骤
- 如果这个类还没有被加载和链接,那先进行加载和链接
- 假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口)
- 加入类中存在初始化语句(如static变量和static块),那就依次执行这些初始化语句
------------------------------------------------------------------------------
【1】https://www.jianshu.com/p/2e818109bb3d
【2】https://blog.csdn.net/zxd8080666/article/details/78087646