java8类加载器示例&类加载1.8和1.8+的区别
示例代码
package com.example.demo;
public class ClassLoaderExample {
public static void main(String[] args) {
// 1.8及以下ClassLoaderExample sun.misc.Launcher$AppClassLoader@18b4aac2
// 1.9+ ClassLoaderExample jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
System.out.println("ClassLoaderExample " + ClassLoaderExample.class.getClassLoader());
// 1.8及以下:ClassLoaderExample getParent sun.misc.Launcher$ExtClassLoader@4c873330
// jdk9+ ClassLoaderExample getParent jdk.internal.loader.ClassLoaders$PlatformClassLoader@26a1ab54
System.out.println("ClassLoaderExample getParent " + ClassLoaderExample.class.getClassLoader().getParent());
// 1.8及以下 ClassLoaderExample getParent null
// jdk9+ ClassLoaderExample getParent getParent null
System.out.println("ClassLoaderExample getParent getParent " + ClassLoaderExample.class.getClassLoader().getParent().getParent());
// 1.8及以下 null
// jdk9+ null
System.out.println("String " + String.class.getClassLoader());
// 1.8及以下 Exception in thread "main" java.lang.NullPointerException
// jdk9+ Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.ClassLoader.getParent()" because the return value of "java.lang.Class.getClassLoader()" is null at
// com.example.demo.ClassLoaderExample.main(ClassLoaderExample.java:18)
System.out.println("String getParent " + String.class.getClassLoader().getParent());
}
}
🌳 类加载器(ClassLoader)结构回顾
Java 的类加载器是分层级的,主要有三种类加载器(JDK 8 及以前):
- Bootstrap ClassLoader(引导类加载器)
- 加载 Java 核心类库,如
java.lang.*。 - 用 C++ 编写,是 JVM 内部的一部分。
- 不是 Java 对象(即不是
ClassLoader的子类实例),因此在 Java 层获取不到它的引用(表现为null)。
- 加载 Java 核心类库,如
- Extension ClassLoader(扩展类加载器)
- 加载
jre/lib/ext/目录下的类。 - 是 Java 编写的,
sun.misc.Launcher$ExtClassLoader实例。
- 加载
- Application ClassLoader(应用类加载器)
- 加载应用程序
classpath下的类。 - 也是 Java 编写的,
sun.misc.Launcher$AppClassLoader实例。
- 加载应用程序
代码运行时打印信息解释
System.out.println("ClassLoaderExample " + ClassLoaderExample.class.getClassLoader());
输出类似于:
ClassLoaderExample sun.misc.Launcher$AppClassLoader@18b4aac2
说明当前类是由应用类加载器加载的。
System.out.println("ClassLoaderExample getParent " + ClassLoaderExample.class.getClassLoader().getParent());
输出:
ClassLoaderExample getParent sun.misc.Launcher$ExtClassLoader@4c873330
AppClassLoader 的父类是 ExtClassLoader,正确无误。
System.out.println("ClassLoaderExample getParent getParent " + ClassLoaderExample.class.getClassLoader().getParent().getParent());
输出:
ClassLoaderExample getParent getParent null
✅ 解释:为什么最后是 null
ExtClassLoader的父类是 Bootstrap ClassLoader。- 但是 Bootstrap ClassLoader 是 JVM 内部实现,不是一个 Java 对象。
- 在 Java 层调用
getParent()时,如果父加载器是 Bootstrap,就会返回null。
👉 换句话说:
ExtClassLoader.getParent() = BootstrapClassLoader → null in Java
所以你看到的是:
AppClassLoader.getParent() = ExtClassLoader
ExtClassLoader.getParent() = BootstrapClassLoader → null
✅ 小结
| 类加载器 | 类名 | getParent() 的结果 |
|---|---|---|
| 应用类加载器 | sun.misc.Launcher$AppClassLoader |
返回 ExtClassLoader |
| 扩展类加载器 | sun.misc.Launcher$ExtClassLoader |
返回 null(实际是 Bootstrap) |
| 引导类加载器 | JVM 内部实现(非 Java 对象) | 无法用 Java 代码直接引用,getParent 为 null |
好的,我们来系统性、严谨地讲解一下 Java 9 模块系统(Project Jigsaw) 引入之后,类加载器机制的变化 —— 特别是与模块(module)系统结合之后的差异。
🔧 Java 9 模块系统与类加载器关系变更详解
一、背景:Project Jigsaw(Java 9 引入)
Java 9 引入了 模块系统(Module System),目的是:
- 增强封装性和可维护性。
- 将 JDK 自身模块化(比如
java.base,java.sql,java.xml等)。 - 支持用户定义模块(module-info.java)。
二、Java 9 之前的类加载器结构(复习)
我们回顾下 JDK 8 及以前的类加载器结构:
BootstrapClassLoader (C++实现,加载核心类库)
↑
ExtClassLoader (Java实现,加载jre/lib/ext下类库)
↑
AppClassLoader (Java实现,加载classpath中的类)
三、Java 9 之后:类加载器结构变化
✅ 主要变化:
- 引入了 Platform ClassLoader(新的中间层)。
- 扩展类加载器
ExtClassLoader被废弃。 - 新的加载器层级结构如下:
BootstrapClassLoader -> 加载 java.base 等核心模块
↑
PlatformClassLoader -> 加载 JDK 提供的其他模块(例如 java.sql)
↑
AppClassLoader -> 加载用户模块(即 classpath 或 modulepath 中的应用模块)
📌 说明:
PlatformClassLoader替代了原来的ExtClassLoader。- 它加载的是 JDK 提供的标准模块,而不是 jre/lib/ext 目录(该目录从 Java 9 开始被废弃)。
四、PlatformClassLoader 特点
你可以通过以下方式访问:
ClassLoader platformClassLoader = ClassLoader.getPlatformClassLoader();
并通过查看其层级:
System.out.println("PlatformClassLoader: " + platformClassLoader);
System.out.println("PlatformClassLoader parent: " + platformClassLoader.getParent());
它的父类仍然是 BootstrapClassLoader(Java 中表现为 null)。
五、类与类加载器的关系在模块系统中的影响
模块系统不仅组织代码包,还与类加载器紧密相关:
| 模块位置 | 类加载器 |
|---|---|
java.base 等核心模块 |
BootstrapClassLoader |
java.sql 等平台模块 |
PlatformClassLoader |
| 用户定义模块 | AppClassLoader |
举个例子:
System.out.println("String.class loader: " + String.class.getClassLoader()); // null(Bootstrap)
System.out.println("java.sql.Driver.class loader: " + java.sql.Driver.class.getClassLoader()); // PlatformClassLoader
System.out.println("你自己的类 loader: " + YourClass.class.getClassLoader()); // AppClassLoader
六、模块系统对反射和访问权限的限制
Java 9 引入模块系统后,对于 setAccessible(true) 等反射操作增加了限制,默认情况下不能访问其它模块中未开放的 package。
你需要:
- 在命令行中添加
--add-opens参数; - 或在模块描述符中添加
opens或exports。
✅ 总结
| Java 版本 | 类加载器结构变化说明 |
|---|---|
| Java 8及以前 | Bootstrap → Ext → App |
| Java 9及以后 | Bootstrap → Platform → App(Ext废弃) |
主要新增:
- PlatformClassLoader:加载平台模块,替代原
ExtClassLoader。 - 模块系统与类加载器绑定更紧密,强调包封装与访问控制。

浙公网安备 33010602011771号