类加载机制
- 类的生命周期
类加载的过程:加载 -> 连接(验证,准备,解析) -> 初始化

- 加载
类加载的第一个阶段,在加载阶段,虚拟机需要完成以下三件事情:
- 通过类的全限定名获得类的二进制字节流.
- 将这个二进制字节流所代表的静态储存结构转换成方法区中的运行时数据结构.
- 在堆中生成代表这个类的唯一class对象,可以通过这个class对象访问到方法区中的数据.
相对于类加载的其他阶段而言,加载阶段(准确地说,是加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,因为开发人员既可以使用系统提供的类加载器来完成加载,也可以自定义自己的类载器来完成加载
- 连接
验证:确保类的加载符合jvm规范
验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
准备:为类的静态变量分配内存,并赋给初始值
准备阶段是正式为类变量分配内存并设置初始值的阶段,这些内存都将在方法区中分配(jdk1.8以后静态变量随class对象一起存放在堆中).
注意: 这里进行分配的只是类变量,也就是用static修饰的变量.而不包括实例变量和成员变量.实例变量会在对象实例化的时候分配在堆中,成员变量则是调用方法的时候进行分配.
这里的初始值是该数据类型的默认值(0,null,false等),而不是显式的赋值.
例如 public static Integer i = 3 ,这里的 i 变量在准备阶段进行了内存分配,并赋予初始值0.
还有关于基本数据类型,如果声明为实例变量是存放在堆中的,而声明为局部变量存放在栈中。
解析:将类中的符号引用转换成直接引用
解析阶段就是虚拟机将常量池中的符号引用替换为直接引用的过程.符号引用就是描述目标的一组符号,可以是任何字面量.字面量:用于表示固定值的符号(token).
直接引用就是直接指向目标的一个指针、相对偏移量或一个间接定位到目标的句柄。(简单描述一下大概就是指向内存区域的指针,这里我不是很懂)
- 初始化
JVM负责对类进行初始化,主要对类变量进行初始化。在Java中对类变量进行初始值设定有两种方式:
-
- 直接声明赋值.如: static int i = 1;
- 先声明,再通过静态代码块赋值. 如: static int i; static{i = 1;}
JVM初始化步骤:
-
- 假如这个类还没有被加载和连接,则程序先加载并连接该类
- 假如该类的直接父类还没有被初始化,则先初始化其直接父类
- 假如类中有初始化语句,则系统依次执行这些初始化语句
类初始化时机: 只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:
-
- 创建类的实例,也就是new的方式
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射(如Class.forName("com.pdai.jvm.Test"))
- 初始化某个类的子类,则其父类也会被初始化
- Java虚拟机启动时被标明为启动类的类(Java Test),直接使用java.exe命令来运行某个主类
文字来源 https://www.pdai.tech.学习记录一下,有误请指正.更多详细内容查看链接:https://www.pdai.tech/md/java/jvm/java-jvm-classload.html

浙公网安备 33010602011771号