JVM(3)—类加载子系统
JVM(3)—类加载子系统
类加载子系统负责从文件或者网络加载Class字节流,读取字节码中的信息,运行时存储到JVM内存中,任何Class字节流都要遵循JVM字节码规范。
类加载执行过程:1.加载。2.链接。3.初始化。

加载
- 读取字节码二进制流。
- 解析字节码二进制流的静态数据转换为运行时JVM方法区数据。
- 生成java.lang.Class对象,放入堆中,作为方法区的访问入口。
- 加载类过程中,父类先加载。

什么时候加载字节码?
- new实例化。 A a = new A()
- 反射。 Class.forName("")
- 子类加载时父类先加载。
- JVM启动时。包含main方法的主类。
- 1.7动态类型语言支持。
链接
- 验证:确保字节码符合虚拟机规范要求。

- 准备:为类变量static赋予初始值。
public class A{
public static int a = 100;
}
// 准备阶段 a = 0 ,初始化阶段 a = 100。
- 解析:将字节码符号引用转换为直接引用。包括类解析,字段解析,方法解析,接口解析。
即将字节码的静态字面关联(字符串,静态)转换为JVM内存中的动态指针关联(指针,动态)。

初始化
-
执行类构造器方法<clinit>()。
-
<clinit>()方法用于完成类的初始化操作。
-
<clinit>()方法由编译器自动生成。
-
<clinit>()方法是对类(静态)变量赋值与执行static代码块。
-
子类执行<clinit>(),会先执行父类<clinit>()。
-
没有类(静态)变量和static代码块,就不会<clinit>()。
-
<clinit>()执行会加同步锁,保证<clinit>()只执行一次。
类加载器

- 启动类加载器:C语言开发。加载Java核心类库。基于沙箱机制,只加载java、javax、sun包开头的类。
- 扩展类加载器:Java语言编写,由sun.misc.Launcher$ExtClassLoader实现。上级加载器为启动类加载器。
- 应用程序类加载器:Java语言编写,由sun.misc.Launcher$AppClassLoader实现。上级加载器为扩展类加载器。是默认的类加载器。
自定义类加载器
- 使用场景:字节码二进制流来自于网络,字节码文件不在指定的lib、ext、classpath路径下,需要对二进制流加工后才能得到字节码。
- Class实例在JVM中是全局唯一的吗?
不同的类加载器加载同一个Class字节码文件后,在JVM中产生的类对象是不同的。
同一个类加载器,Class实例在JVM中才是全局唯一。
双亲委派机制
加载类时加载器逐级将加载任务向上委派至启动类加载器,然后逐级向下尝试加载,直至加载完成。

优点:保护了类不会被重复加载,禁止用户污染java开头的核心包。
package java;
public class Custom {
public static void main(String[] args) {
System.out.println("java");
}
}
// 沙箱机制,以java开头的包将拒绝加载
java.lang.SecurityException: Prohibited package name: java

浙公网安备 33010602011771号