类的加载过程是Java虚拟机将类的字节码文件加载到内存中,并转换为运行时数据结构的过程。类加载器负责加载类的任务。
Java虚拟机提供了三种类加载器:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和应用程序类加载器(Application ClassLoader):
1. 启动类加载器(Bootstrap ClassLoader):
- 启动类加载器是最顶层的类加载器,负责加载Java核心类库(如rt.jar)等。它是用C++实现的,是虚拟机的一部分,不继承自java.lang.ClassLoader类。
- 启动类加载器在Java虚拟机启动时被创建,它负责加载JRE的
核心类库
,是虚拟机自身的一部分,不是普通Java类。由于其特殊性,无法直接获取启动类加载器的引用。
2. 扩展类加载器(Extension ClassLoader):
- 扩展类加载器是用Java编写的类加载器,负责加载Java的扩展类库(如
jre/lib/ext
目录下的jar包)。它是sun.misc.Launcher$ExtClassLoader类
的实例。 - 扩展类加载器是由启动类加载器加载的,它的
父类加载器是启动类加载器
。扩展类加载器通常用于加载Java的扩展类库,提供给应用程序使用。
3. 应用程序类加载器(Application ClassLoader):
- 应用程序类加载器是用Java编写的类加载器,负责加载应用程序的类文件。它是
sun.misc.Launcher$AppClassLoader类
的实例。 - 应用程序类加载器是由扩展类加载器加载的,它的
父类加载器是扩展类加载器
。应用程序类加载器是最常用的类加载器,用于加载应用程序的类文件和资源,通常我们自己写的类默认应用程序类加载器进行加载的。
如何获取
启动类加载器是虚拟机的一部分,无法直接获取其引用,但可以通过 ClassLoader.getSystemClassLoader()
获取应用程序类加载器和扩展类加载器的引用。
获取应用程序类加载器(Application ClassLoader)
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
System.out.println("Application ClassLoader: " + appClassLoader);\
获取扩展类加载器(Extension ClassLoader)
ClassLoader extClassLoader = appClassLoader.getParent();
System.out.println("Extension ClassLoader: " + extClassLoader);
加载步骤
加载(Loading)
:类加载器通过类的全限定名
来定位类的字节码文件,并将字节码文件
加载到内存中。链接(Linking)
:链接阶段分为验证(Verification)
、准备(Preparation)
和解析(Resolution)
三个步骤。- 验证:确保加载的类
符合Java虚拟机规范
,不会破坏虚拟机的稳定性。 - 准备:为类的
静态变量
分配内存并赋予初始值。 - 解析:将
符号引用
转换为直接引用。
- 验证:确保加载的类
初始化(Initialization)
:当对类进行初始化时,执行类构造器方法( <clinit> )
,静态变量赋值
,这里的赋值是等操作。
双亲委派模型
类加载器采用双亲委派模型,即除了启动类加载器外,每个类加载器都有一个父类加载器。当一个类加载器收到加载请求时,会先委托父类加载器尝试加载类
,只有在父类加载器无法加载时,才会自己尝试加载。这样可以保证类加载的顺序和避免重复加载。