JVM:类加载的过程
java类加载过程可分为3个步骤,分别为:加载、连接(验证、准备、解析)和初始化过程,这些都是在程序运行期间去完成的。
-
加载
加载阶段是把类的.class文件中的二进制读到内存中,将其放在运行时数据区的方法区中,然后在堆中创建.class对象。加载的顺序为:.class文件---->读取到内存---->数据放到方法区----->在堆中创建.class对象---->提供方法区的接口
-
验证
验证加载类的正确性,我们只需知道验证是的意思即可,虽然验证阶段是非常重要的,但不是必须的,他对程序运行没有什么影响
-
准备
准备阶段是非常重要的一个步骤,当完成验证步骤时,jvm便会开始为类变量(类变量:static修饰的变量)分配内存并初始化。但要注意一点的是这里的初始化并不是用户代码中写的值,而是系统默认的初始化的值
例如以下代码:
public static int num = 1;
在准备阶段num的值为0,而不是1。
但有一种情况,再准备阶段,类变量将赋值用户代码中写的值,那就是用static final修饰的类变量,因为final关键字在java便是常量,必须赋予初始值且不能被改变。
-
解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
**符号引用(Symbolic References):**符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义的定位到目标即可。
**直接引用(Direct References):**直接引用可以是直接指向目标的指针、相对偏移量或是一个能简介定位到目标的句柄。
-
初始化
初始化也是jvm类加载中的重点,到了初始化阶段,用户定义的java代码才开始真正的去运行。在初始化阶段会为类成员变量(类成员变量:除了被static 修饰的变量 ,其他类型的变量)分配内存。为类变量初始化用户代码的值。
什么时候需要对类初始化
- 使用new该类实例化对象的时候;
- 读取或设置类静态字段的时候(凡是被final修饰不不不其实更准确的说是在编译器把结果放入常量池的静态字段除外) ;
- 调用类静态方法的时候;
- 使用反射Class.forName(“xxxx”)对类进行反射调用的时候,该类需要初始化;
- 初始化一个类的时候,有父类,先初始化父类(注:1. 接口除外,父接口在调用的时候才会被初始化;2.子类引用父类静态字段,只会引发父类初始化);
- 被标明为启动类的类(即包含main()方法的类)要初始化;