装载类子系统
- 类加载器
- 字节码调节器
- 类加载运行时数据区
类加载器
将class文件加载进jvm的方法去,并在方法去中创建一个java.lang.Class对象作为外界访问这个类的接口。实现这个动作的代码模块称为类加载器。
类加载器分类
- 启动类加载器(Bootstrap ClassLoader)
- 扩展类加载器
- 应用程序类加载器
- 自定义加载器
启动类加载器
它是Java加载系统的根部,它负责加载Java核心类库(JAVA_HOME/jre/lib/rt.jar中的类库),由于启动类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不同于其他的类加载器,启动类加载器并不继承自java.lang.ClassLoader类。
扩展类加载器
这是一个由Sun的Extension ClassLoader实现的,它负责加载Java的扩展库
(JAVA_HOME/jre/lib/ext或者由系统变量java.ext.dirs指定路径中的类库)。
开发者可以直接使用标准扩展目录(ext目录)做类库的扩展。
应用程序类加载器
这是ClassLoader中getSystemClassLoader()方法的返回值,所以也称为系统类加载器。
它负责加载环境变量CLASSPATH或者-classpath/-cp命令行选项指定路径中的类库。该类加载器是用户自定义加载器的默认父加载器。
自定义加载器
自定义类加载器(Custom ClassLoader):Java允许我们自定义类加载器,只需要继承java.lang.ClassLoader类,并重写findClass方法即可。
这样可以让Java类具有动态加载和热加载的能力,提高了Java程序的灵活性。
类加载过程
- 加载:
- 连接:
2.1. 验证
2.2. 准备
2.3. 解析 - 初始化
加载:
- 加载是指Java虚拟机查找字节流(查找.class文件),并且根据字节流创建java.lang.class对象的过程。
- 这个过程,将类的.class文件中的二进制数据读入内存,凡在运行时数据区的方法区内。然后就在堆中创建java.lang.class对象,用来封装类在方法去中的数据结构
- 类加载阶段
- (1) Java虚拟机将.class文件读入内存,并为之创建一个Class对象。
- (2)任何类被使用时系统都会为其创建一个且仅有一个Class对象。
- (3)这个Class对象描述了这个类创建出来的对象的所有信息,比如有哪些构造方法,都有哪些成员方法,都有哪些成员变量等。
连接:
验证
- 验证阶段作用是保住Class文件的字节流包含的信息符合JVM规范,不会给JVM造成危害。如果验证失败,就会抛出一个java.lang.VerifyError异常或其子类异常。验证过程分为四个阶段:
- (1)文件格式验证:验证字节流文件是否符合Class文件格式规范,并且能被当前虚拟机正确处理。
- (2)元数据验证:是对字节码描述信息惊喜语义分析,以保证其描述的信息符合java语言规范要求
- (3)字节码验证:主要是惊喜数据流和控制流的分析,保证被校验类的方法在运行时不会危害虚拟机
- (4)符号引用验证:符号引用验证发生在虚拟机将符号转化为直接引用的时候,这个转化动作将在解析阶段发生。
准备
- 准备阶段为变量分配内存并设置类变量的初始化。这个阶段分配的仅为类的变量,而不包括类的实例变量。对于非final的变量,JVM会将其设置成“零值”,而不是赋值语句的:private static int size = 12 。那么在这个阶段,size的值为0,而不是12.但非final修饰的类变量将会赋值成真实的值。
解析
- 解析过程是将常量池内的符号引用替换成直接引用,主要包括四类型引用解析。类或接口的解析,字段解析、方法解析、接口方法解析。
初始化:
双亲委派模型
如果一个类接受到请求,他首先将请求交给父类加载器,直至找到启动类加载器,如果父类加载器加载失败,当前类加载器才会自己加载类。
为什么要使用双亲委派模型:防止类重复加载,保护核心的类
字节码校验器
字节码校验器的主要作用是确保加载的字节码文件符合Java虚拟机的规范,不会造成虚拟机的安全问题。它会检查字节码文件的格式、标识符、常量、堆栈、方法和类结构等信息,如果字节码文件不合规范,字节码校验器会拒绝加载该文件。
类加载运行时数据区
类加载运行时数据区的主要作用是存储加载的类的元数据信息合类的字节码等数据。这些信息包括类的名称、访问修饰符、继承关系、接口信息、字段信息、方法信息等。载Java虚拟机执行行字节码时,会使用到这些元数据信息。