JavaSE - 反射-类加载机制与类加载器
本节学习目标:
- 了解类加载的过程;
- 了解类加载器的种类和机制。
1. 类加载机制
1.1 类加载的过程
一个类从加载到内存中到从内存中卸载一共经历了以下流程:
- 加载(Loading):
Java虚拟机(或类加载器)根据类的全限定类名查找对应的字节码文件(.class),读取并创建一个对应的Class
实例。 - 验证(Verification):
检查字节码文件的字节流中包含的信息是否符合当前Java虚拟机要求,不会危害Java虚拟机安全。主要以下四种验证:- 文件格式验证:基于字节流验证,验证字节流是否符合当前字节码文件格式的规范,能被当前虚拟机处理。验证通过后会将字节流存储至内存的方法区;
- 元数据验证:基于方法区的存储结构验证,对字节码进行语法验证,确保元数据符合Java语言规范;
- 字节码验证:基于方法区的存储结构验证,分析数据流和控制流保证运行时不会对Java虚拟机的安全造成威胁;
- 符号引用验证:基于方法区的存储结构验证,发生在解析阶段,验证符号引用是否能解析为直接引用,确保解析流程正常执行。
- 准备(Preparation):
为类中的类变量(静态变量)分配内存空间并设置初始值(不会直接初始化为指定值)。(不包含静态常量,它们的引用在编译期间就已经被替换为对应值了) - 解析(Resolution):
将内存的常量池内的符号引用解析为直接引用(即把引用解析为内存地址)。 - 初始化(Initialization):
类中的成员按照以下顺序进行初始化(上先下后):- 父类静态成员和静态代码块;
- 子类静态成员和静态代码块;
- 父类普通成员和非静态代码块;
- 父类构造方法;
- 子类普通成员和非静态代码块;
- 子类构造方法。
1.2 类初始化的时机
以下操作会触发类的初始化:
- 使用
new
关键字创建某个类的对象; - 使用类加载器的
loadClass()
方法或者Class
类的forName()
方法加载一个类; - 访问类的静态成员(访问或修改静态变量、访问静态方法);
- 反射调用某个类;
- 初始化某个类的子类;
- 使用
java
命令运行某个主类(拥有main()
方法的类)。
2. 类加载器
类加载器(ClassLoader)通过类的全限定类名查找对应的字节码文件,并将它们加载进内存中。
ClassLoader
类是一个抽象类,位于java.lang
包下,用于定义类加载器的行为及实现策略。
2.1 类加载器的种类
Java提供了三种类加载器:
- 核心类加载器(Bootstrap ClassLoader):负责加载核心类库
由本地代码实现(C或C++),用于加载Java虚拟机启动的核心类。它负责加载以下内容:%JAVA_HOME%\jre\lib
目录下特定名称的类库;- Java虚拟机参数
-Xbootclasspath
指定路径下特定名称的类库; - Java虚拟机属性
sun.boot.class.path
指定路径下特定名称的类库。
- 扩展类加载器(Extension ClassLoader):负责加载扩展类库
类sun.misc.Launcher.ExtClassLoader
。Java虚拟机启动时由BootstrapClassLoader
加载并初始化,只有一个实例。它负责加载以下内容:%JAVA_HOME%\jre\lib\ext
目录下特定名称的类库;- Java虚拟机属性
java.ext.dirs
指定路径下特定名称的类库;
- 应用类加载器(Applicat