类加载器

一、类加载器是什么

**类加载器(ClassLoader)**负责把 .class 文件加载到 JVM 内存中,并生成对应的 Class 对象。

本质:

  • 输入:字节码(.class 文件)
  • 输出:Class<?> 对象(方法区/元空间中)

二、类加载过程

类加载器主要参与的是:

1
加载(Loading) → 验证 → 准备 → 解析 → 初始化

类加载器只负责第一步:加载(Loading)

具体做:

  1. 根据类的全限定名找到字节码
  2. 读取 .class
  3. 转换为 JVM 内部结构
  4. 生成 Class 对象

三、类加载器的分类

Java 中有三种核心类加载器:

3.1 启动类加载器(Bootstrap ClassLoader)

  • 用 C++ 实现(不是 Java 类)

  • 负责加载:

    1
    <JAVA_HOME>/lib
  • 比如:

    • rt.jar(JDK8)
    • 核心类:StringObject

特点:

  • 最顶层加载器
  • 没有父加载器

3.2 扩展类加载器(Extension ClassLoader)

  • Java 实现

  • 加载目录:

    1
    <JAVA_HOME>/lib/ext

3.3 应用类加载器(Application ClassLoader)

  • 又叫 系统类加载器

  • 负责加载:

    1
    classpath
  • 也就是你写的代码

面试重点:

默认情况下,我们写的类都是它加载的

3.4 自定义类加载器(User-defined)

你可以继承 ClassLoader 自己实现:

1
2
3
4
5
6
class MyClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) {
// 自定义加载逻辑
}
}

使用场景:

  • 热部署(Tomcat)
  • 加密 class
  • 动态加载

四、双亲委派模型 ⭐(重点)

4.1 什么是双亲委派?

当一个类加载请求来时:

1
当前加载器 → 先问父加载器 → 一直往上 → Bootstrap

加载顺序:

1
2
3
4
5
Application

Extension

Bootstrap

4.2 工作流程

假设要加载 java.lang.String

  1. Application 收到请求
  2. 交给 Extension
  3. Extension 交给 Bootstrap
  4. Bootstrap 找到了 → 加载成功
  5. 返回结果

4.3 为什么要这样设计?

  1. 防止核心类被篡改

你写一个假的:

1
2
package java.lang;
public class String {}

不会生效,因为:

  • Bootstrap 已经加载了真正的 String
  1. 避免重复加载

同一个类只会被加载一次

4.4 注意点(面试高频)

双亲委派不是强制的

  • 可以被打破(如 Tomcat)

五、如何打破双亲委派

典型场景:

5.1 重写 loadClass 方法

  • 类加载器在进行类加载的时候,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成(调用父加载器 loadClass() 方法来加载类)。
  • 重写 loadClass() 方法之后,我们就可以改变传统双亲委派模型的执行流程。

5.1 Tomcat

  • 每个 Web 应用有独立 ClassLoader
  • 可以加载不同版本的类

为什么要打破?

  • 不同应用可能依赖不同版本的库

5.2 SPI(Service Provider Interface)

比如:

  • JDBC
  • ServiceLoader

原因:

  • 核心类需要加载第三方实现

解决:

  • 线程上下文类加载器(Thread Context ClassLoader)

六、类加载器的核心方法

1
loadClass()

流程:

1
2
3
1. 检查是否已加载
2. 委派父加载器
3. 自己加载(findClass)

七、面试高频总结

⭐ Q1:类加载器有哪些?

  • Bootstrap(启动类加载器)
  • Extension(扩展类加载器)
  • Application(应用程序类加载器)
  • 自定义

⭐ Q2:双亲委派模型作用?

  • 防止篡改核心类
  • 避免重复加载

⭐ Q3:什么时候会破坏双亲委派?

  • 重写 loadClass 方法
  • Tomcat
  • SPI(JDBC)

⭐ Q4:类加载器负责什么?

只负责:

  • 加载字节码 → 生成 Class 对象

八、一句话总结

类加载器负责把 .class 加载进 JVM,而双亲委派模型保证了加载的安全性和唯一性。