类加载器(Class Loader)
简介
类加载器(Class Loader)是 Java 虚拟机(JVM)的一部分,负责将类的字节码加载到 JVM 中,并转换成可以执行的 Java 类。
分类
- 引导类加载器(Bootstrap ClassLoader)
- 自定义类加载器(User-Defined ClassLoader)
引导类加载器
- 该类加载器使用 C++ 语言实现,是虚拟机自身的一部分
- 仅限 HotSpot,有部分 Java 虚拟机,整个虚拟机都是 Java 编写的,Bootstrap ClassLoader 也是使用 Java 语言编写的。
- 因为是 C++ 语言实现,所有在 Java 中获取该加载器的时候为 null,都不是同一个编程语言,当然不属于 Java 中的对象的概念,但是并不是指没有该类加载器
自定义类加载器
- 所有派生于 ClassLoader 的类加载器,都属于自定义类加载器
- 不同 JDK 版本,不管是 ExtClassLoader 还是 AppClassLoader 或者是 PlatformClassLoader 或者其他的类加载器,都派生于 ClassLoader
- JDK8 中:ExtClassLoader 和 AppClassLoader 是 Launcher 内部类,
- JDK17 中:PlatformClassLoader 和 AppClassLoader 是 ClassLoaders 内部类,
测试
java
public class TestClassLoader {
public static void main(String[] args) {
Class<TestClassLoader> aClass = TestClassLoader.class;
//这里为了符合打印的顺序,符合双亲委派逻辑图的顺序
System.out.println(aClass.getClassLoader().getParent().getParent()); //获取该类的类加载器的父级的父级(启动类/引导类加载器)
System.out.println(aClass.getClassLoader().getParent()); //获取该类的类加载器的父级(不是父类)
System.out.println(aClass.getClassLoader()); //获取该类的类加载器
}
}
java
//在 JDK8 中执行结果
null
sun.misc.Launcher$ExtClassLoader@4554617c
sun.misc.Launcher$AppClassLoader@18b4aac2
java
//在 JDK11 中执行结果
null
jdk.internal.loader.ClassLoaders$PlatformClassLoader@7c30a502
jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
java
//在 JDK17 中执行结果
null
jdk.internal.loader.ClassLoaders$PlatformClassLoader@511baa65
jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
作用
引导类加载器
- 加载 Java 核心库,用于提供 JVM 自身需要的类,为了安全考虑,只加载部门包名为 java、javax、sun 开头的类
- 加载 ExtClassLoader、AppClassLoader、PlatformClassLoader
ExtClassLoader(JDK 8)
PlatformClassLoader(JDK 17)
AppClassLoader
该类是程序中默认的类加载器,一般情况,都是由该类完成加载
- java
//获取系统类加载器 System.out.println(ClassLoader.getSystemClassLoader());
自定义类加载器
- 一般情况,以上三种类加载器足够使用了,肯定有特殊情况不够用,哪些情况需要用户自定义类加载器呢?
- 隔离加载类
- 修改加载方式
- 扩展加载源
- 防止源码泄露
如何自定义类加载器
双亲委派模型(Parents Delegation Model)
图中的箭头不是表示父类关系,很多程序员当成 Java 中的 extends 继承关系了,这是错的,
图中的箭头只是为了表示委派关系
双亲委派模型在 JDK1.2 期间被引入,但不是强制性的约束,而是 Java 设计者推荐给开发者的一种实现方式,后续会讲到破坏双亲委派模型的情况。