java当中的类加载器
在 Java 中,类加载器(ClassLoader)是 JVM 的核心组件之一,负责将字节码文件(.class
文件)加载到内存中并生成对应的 Class
对象。Java 的类加载机制遵循双亲委派模型,即一个类加载器在加载类时,会先委托其父类加载器尝试加载,只有在父类加载器无法加载时才会自己加载。
下面分别从 JDK 8 和 JDK 11 的角度详细介绍类加载器的结构、关系以及它们所加载的 JAR 包。
JDK 8 中的类加载器
1. 类加载器的层次结构
在 JDK 8 中,类加载器分为以下几种:
(1) Bootstrap ClassLoader(引导类加载器)
- 描述:
- 是用 C++ 实现的本地类加载器,负责加载 JVM 核心类库。
- 它是最顶层的类加载器,没有父类加载器。
- 加载路径:
$JAVA_HOME/lib
目录下的核心类库,例如:rt.jar
(包含java.lang.*
、java.util.*
等核心类)charsets.jar
jce.jar
jsse.jar
- 特点:
- 不继承自
java.lang.ClassLoader
,而是由 JVM 自身实现。 - 加载的类对应用程序不可见。
- 不继承自
(2) Extension ClassLoader(扩展类加载器)
- 描述:
- 负责加载 Java 的扩展类库。
- 加载路径:
$JAVA_HOME/lib/ext
或者系统属性java.ext.dirs
指定的目录。
- 特点:
- 是
sun.misc.Launcher$ExtClassLoader
的实例。 - 其父类加载器是
Bootstrap ClassLoader
。
- 是
(3) Application ClassLoader(应用程序类加载器)
- 描述:
- 又称为系统类加载器(System ClassLoader),负责加载用户程序的类。
- 加载路径:
-classpath
或-cp
指定的路径。- 默认情况下是当前工作目录。
- 特点:
- 是
sun.misc.Launcher$AppClassLoader
的实例。 - 其父类加载器是
Extension ClassLoader
。
- 是
(4) Custom ClassLoader(自定义类加载器)
- 描述:
- 开发者可以通过继承
java.lang.ClassLoader
来实现自己的类加载器。
- 开发者可以通过继承
- 用途:
- 动态加载类。
- 加载加密的类文件。
- 实现模块化隔离(如 OSGi)。
2. 双亲委派模型
- 流程:
- 当某个类加载器收到加载类的请求时,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器。
- 只有当父类加载器无法加载这个类时(即在父类加载器的范围内找不到该类),子类加载器才会尝试自己加载。
- 优点:
- 避免重复加载:保证同一个类只会被加载一次。
- 安全性:防止用户自定义的核心类(如
java.lang.String
)覆盖 JDK 提供的核心类。
JDK 11 中的类加载器
从 JDK 9 开始,Java 引入了模块化系统(JPMS,Java Platform Module System),并对类加载器的结构进行了调整。以下是 JDK 11 中类加载器的主要变化:
1. 类加载器的层次结构
(1) Bootstrap ClassLoader(引导类加载器)
- 描述:
- 仍然是最顶层的类加载器,负责加载 JVM 核心模块。
- 加载路径:
- 不再依赖于传统的
$JAVA_HOME/lib
目录,而是基于模块化系统(java.base
等模块)。 - 加载的模块包括:
java.base
java.logging
java.xml
- 等等。
- 不再依赖于传统的
- 特点:
- 仍然由 JVM 自身实现,不继承自
java.lang.ClassLoader
。
- 仍然由 JVM 自身实现,不继承自
(2) Platform ClassLoader(平台类加载器)
- 描述:
- 替代了 JDK 8 中的
Extension ClassLoader
。
- 替代了 JDK 8 中的
- 加载路径:
- 负责加载标准的 Java SE 平台模块(非核心模块)。
- 这些模块通常位于
$JAVA_HOME/jmods
目录下。
- 特点:
- 是
jdk.internal.loader.ClassLoaders$PlatformClassLoader
的实例。 - 其父类加载器是
Bootstrap ClassLoader
。
- 是
(3) Application ClassLoader(应用程序类加载器)
- 描述:
- 功能与 JDK 8 中的应用程序类加载器相同。
- 加载路径:
- 仍然是
-classpath
或-cp
指定的路径。
- 仍然是
- 特点:
- 是
jdk.internal.loader.ClassLoaders$AppClassLoader
的实例。 - 其父类加载器是
Platform ClassLoader
。
- 是
(4) Custom ClassLoader(自定义类加载器)
- 描述:
- 与 JDK 8 中的自定义类加载器相同,开发者可以按需实现。
2. 模块化系统的影响
- 模块化系统:
- 在 JDK 9+ 中,所有的 JDK 类都被组织成模块(Module),每个模块都有明确的边界和依赖关系。
- 类加载器需要根据模块的依赖关系来加载类。
- 影响:
rt.jar
和tools.jar
被移除,取而代之的是模块化的 JAR 文件(.jmod
)。$JAVA_HOME/lib/ext
不再存在,扩展机制被废弃。- 类加载器的职责更加清晰,减少了传统类路径(Classpath)的混乱。
总结对比
特性 | JDK 8 | JDK 11 |
---|---|---|
引导类加载器 | 加载 $JAVA_HOME/lib 下的核心类库 | 加载模块化系统中的核心模块(如 java.base ) |
扩展类加载器 | 负责 $JAVA_HOME/lib/ext | 被 Platform ClassLoader 替代 |
平台类加载器 | 无 | 新增,负责加载标准 Java SE 平台模块 |
应用程序类加载器 | 负责 -classpath 指定的路径 | 功能不变 |
模块化支持 | 无 | 基于模块化系统 |
通过以上对比可以看出,JDK 11 的类加载器在结构上更加清晰,并且适应了模块化系统的引入。