臭名昭著aTrust隔离计划1.臭名昭著aTrust隔离计划2.VPN原理与aTrust隔离网络实践3.docker-easyconnect到底做了什么4.TUN(tunnel-隧道-虚拟网卡)模式
个人项目
personal(个人展示)GitHub Actions 自动部署个人展示项目
基于Quartz搭建的个人博客1.Quartz个人博客使用教程2.使用 rsync 增量部署 Quartz 博客3.使用 GitHub Actions 自动部署 Quartz 博客5.域名绑定6.CDN加速7.Google 搜索收录排查:为什么关键词搜得到别人,却搜不到我的网站?Obsidian、双向链接与知识图谱
架构设计
分布式分布式事务RPC原理
旅行
行程攻略青岛三日游行程攻略
前端
NginxNginx配置与反向代理入门
Nodenpm与npx的区别
数据库
mysql01.MySQL基础语法与约束02.MySQL数据库类型03.MySQL多表查询04.MySQL 索引05.MySQL 事务06.MySQL 隔离级别07.MySQL MVCC08.MySQL 锁09.EXPLAIN10.慢查询与 SQL 优化
mysql面试题01.索引问题02.事务与隔离级别03.锁机制04.存储引擎与性能优化05.用户权限、字符集与备份恢复
mysql实战01.EXPLAIN实战02.测试环境菜单误删排查与恢复03.MySQL IN 详解
网络
网络安全1.无线监听网卡苹果M系列虚拟机安装Kali Linux教程3.kali怎么使用RTL8812AU4.kali基础命令
网络基础进程之间怎样通过网络传递数据
网址常用网址
中间键
esElasticsearch 入门
mq
RabbitMQRabbitMQ高级RabbitMQ基础
1. MQ 基础2. MQ 核心角色与代码对应3. MQ Consumer Group 与消费模式4. SOFAMQ 账户变更代码实践5. MQ 可靠性问题6. 消息幂等
redis缓存击穿、穿透与雪崩Redis 分布式锁Redis 缓存问题Redis 数据结构
AI
使用说明
第三方插件&技能简介Archify使用与安装指南geekgeekRun使用OfferFlow使用指南Ponytail使用指南Skills Manager使用指南
CodexCodex CLI与IDE区别及使用指南Codex Hook单独配置与提交通知Codex MCP安装与使用指南Codex第三方插件安装与使用指南
Agent开发0-学习路线1.LLM、Token、上下文窗口与模型参数2.大模型 API、请求参数与响应结构3.Spring AI ChatClient4.Prompt、System Prompt、Prompt 模板6.结构化输出、JSON Schema7.SSE 流式响应8.会话 ID、聊天记录、Redis9.超时、重试、限流、降级10.*完成可运行聊天接口11.Function Calling、Tool Calling 原理12.用 Java 方法定义 Tool13.工具参数设计和校验14.实现订单查询工具15.实现物流查询工具16.实现库存查询工具17.多个工具自动选择18.工具异常、超时、重试
diy主机
主机零件学习1.CPU2.主板3.内存4.显卡5.硬盘6.散热7.风扇8.机箱热门型号价格表
捡垃圾diy-13600kf+5060diy-14600kf+5070
English高频词汇英文基础语法简单句子音标
GitGit常用命令Sublime Merge 使用指南
Java
工具库Caffeine本地缓存Reactor教程
工作实践如何使用@Async线程池使用与排查线上服务 CPU 使用率过高排查压测下RPC接口大量失败排查记录
基础1.HashMap2.ConcurrentHashMap3.HashSet4.final5.static6.volatile7.AtomicInteger8.String动态代理反射锁与线程同步线程注解
面试题1.HashMap 存储在方法内是线程安全的吗2.ArrayList参数传递与引用重新赋值3.== 和 equals 的区别、hashcode4.重载和重写的区别5.String、StringBuffer、StringBuilder区别及使用场景6.接口和抽象类7.ArrayList 与 LinkedList 的区别和扩容机制8.HashMap 和 Hashtable 的区别及底层实现9.Object 和 Objects 的区别10.ThreadLocal的原理和使用场景11.字节码是什么及作用12.Java类加载器有哪些13.双亲委派模型14.Java异常体系15.GC是什么16.GC如何判断对象可以被回收
面试总结0.HR面试模板1.面试一2.面试二3.面试三笔试
网络与 IO(黑马程序员-纯理论)01-网络编程基础02-IO模型与零拷贝03-BIO04-NIO基础与缓冲区05-NIO通道与选择器06-AIO
juc00-目录01-进程与线程02-线程同步与通信03-并发设计模式04-Java内存模型05-CAS与原子类06-ThreadLocal07-阻塞队列08-线程池使用与原理09-任务调度10-ForkJoin与享元模式11-AQS12-ReentrantLock13-读写锁14-并发协作工具15-ConcurrentHashMap16-CopyOnWrite与同步容器17-SkipListMap18-非阻塞队列
juc(工作常见)Java并发编程三个重点拆解
jvm1. JVM运行时数据区
Spring1.Spring IoC、DI与构造方法注入CGLIB、Byte Buddy 与 Spring AOPSpring 常用注解详解Spring Bean 生命周期
Spring MVC异常处理机制
linux常用命令
mac快捷键终端常用操作
python
基础01.Python是什么,为什么要安装Python02.Python项目中.venv是什么03.Python基础语法
基础实战sql替换
HTTPXHRMS员工详情接口调用(Python HTTPX)
windowswindows激活

一、💡 一句话理解

核心结论

Java 常见的类加载器有:启动类加载器、平台类加载器、应用类加载器和自定义类加载器。前三个由 JDK 提供,开发者也可以继承 ClassLoader 实现自己的加载规则。

二、🧭 理论:它是什么

2.1 类加载器是什么,有什么用

类加载器(ClassLoader)是 JVM 中负责查找并加载 Java 类的组件。

Java 代码编译后会生成 .class 字节码文件。当 JVM 第一次需要某个类时,类加载器会找到对应的字节码,将它读入 JVM,并创建可以被程序使用的 Class 对象。

根据类名查找 .class 文件
          ↓
读取类的字节码
          ↓
交给 JVM 创建 Class 对象
          ↓
程序创建对象、调用方法

例如执行 new User() 时,JVM 必须先通过类加载器找到并加载 User 类,然后才能创建 User 对象。

类加载器主要有以下作用:

  • 加载类:从 JDK、项目目录或 JAR 包中找到需要的类。
  • 按需加载:通常在第一次真正使用某个类时才加载,避免一次加载所有类。
  • 保护核心类:配合双亲委派机制,避免应用中的同名类替换 Java 核心类。
  • 支持特殊场景:可以实现插件加载、热部署、类隔离等功能。

记忆方式

类加载器就是 JVM 的“类文件搬运工”:找到 .class 字节码并加载进 JVM,让程序能够创建对象和调用方法。

2.2 四类加载器

类加载器主要负责加载
启动类加载器(Bootstrap ClassLoader)java.lang 等 Java 核心类
平台类加载器(Platform ClassLoader)Java 平台模块中的类
应用类加载器(Application ClassLoader)classpath、模块路径中的应用类
自定义类加载器插件、热部署、类隔离等特殊来源的类

版本区别

JDK 8 常说的扩展类加载器(Extension ClassLoader),从 JDK 9 开始被平台类加载器取代。

2.3 这些类具体指什么

2.3.1 核心类

核心类是 Java 程序运行必不可少的基础类,例如:

java.lang.String
java.lang.Object
java.lang.Thread
java.util.ArrayList

它们通常由启动类加载器加载。

2.3.2 Java 平台模块中的类

JDK 9 开始,JDK 自带的功能被拆分成多个模块:

模块主要功能
java.base字符串、集合、线程等基础功能
java.sqlJDBC 数据库访问
java.xmlXML 处理
java.net.httpHTTP 客户端

java.base 中最基础的类主要由启动类加载器加载,其他一些平台模块中的类由平台类加载器加载。

两者不是完全分开的

核心类本身也属于 Java 平台模块。例如 String 属于 java.base 模块,只是因为它非常基础,所以通常单独称为核心类。

2.3.3 classpath 和模块路径中的应用类

这部分主要包括:

  • 自己编写的类,例如 com.example.UserService。
  • 项目引入的第三方依赖,例如 Spring、MySQL 驱动中的类。

classpath 告诉 JVM 去哪些目录和 JAR 包中寻找类:

java -cp target/classes:lib/mysql.jar com.example.Main

JDK 9 还提供了模块路径(module path),用于查找带有明确模块名称和依赖关系的应用模块。普通 Spring Boot 项目通常主要使用 classpath。它们一般由应用类加载器加载。

快速区分:

Java 运行必需的基础类   → 核心类
JDK 自带的其他功能类    → Java 平台模块中的类
自己写的类和第三方依赖  → classpath 或模块路径中的应用类

2.3.4 自定义类加载器加载的类

这不是某一种固定的 Java 类,而是指程序通过自定义类加载器,按照特殊规则加载的类。常见场景有:

  • 插件:程序运行时加载外部 JAR,例如 IDE 加载 Java、Git 等插件。
  • 热部署:丢弃旧类加载器,再用新类加载器加载修改后的类,减少整个程序重启。
  • 类隔离:让不同插件分别使用不同版本的同一个依赖,避免版本冲突。
  • 特殊来源:从网络、数据库、加密文件或动态生成的字节码中加载类。

类隔离示例

插件 A 使用 Jackson 2.13,插件 B 使用 Jackson 2.17。即使两个类的完整名称相同,只要定义它们的类加载器不同,JVM 就会把它们视为不同的类。

JVM 判断一个类身份的依据是:

类的完整名称 + 定义它的类加载器

一句话理解:普通类加载器按照 JDK 默认规则找类,自定义类加载器允许程序决定去哪里找、怎样读取以及怎样隔离类。

三、⚙️ 理论:它是怎么工作的

类加载器通常采用双亲委派机制:收到加载请求后,先交给父加载器;父加载器找不到时,自己再尝试加载。

应用类加载器 → 平台类加载器 → 启动类加载器

这样可以避免核心类被应用程序中的同名类替换。

延伸阅读:13.双亲委派模型

四、🚀 实践:查看类加载器

4.1 最小验证

public class ClassLoaderDemo {
    public static void main(String[] args) {
        // 当前应用类通常由应用类加载器加载
        System.out.println(ClassLoaderDemo.class.getClassLoader());
 
        // String 属于核心类,由启动类加载器加载;Java 中通常显示为 null
        System.out.println(String.class.getClassLoader());
 
        // 获取平台类加载器
        System.out.println(ClassLoader.getPlatformClassLoader());
    }
}

String.class.getClassLoader() 返回 null,不代表没有加载器,而是启动类加载器不能直接表示为普通 Java 对象。

五、🎤 面试时怎么说

5.1 30 秒标准回答

Java 常见的类加载器有启动类加载器、平台类加载器、应用类加载器和自定义类加载器。启动类加载器负责核心类,平台类加载器负责平台模块,应用类加载器负责项目 classpath 或模块路径中的类。它们通常遵循双亲委派机制,先让父加载器尝试加载,从而避免核心类被重复加载或被同名类替换。JDK 8 中的扩展类加载器,在 JDK 9 后被平台类加载器取代。

六、📌 总结

  • 核心类:启动类加载器。
  • 平台类:平台类加载器。
  • 项目类:应用类加载器。
  • 特殊加载规则:自定义类加载器。
  • 记忆顺序:启动 → 平台 → 应用 → 自定义。

七、📚 官方资料