Skip to content

父类加载器和子类加载器有什么区别

在 Java 的类加载体系中,父类加载器子类加载器 的区别主要体现在 加载范围层级关系职责分工 上。父类加载器负责加载更核心、更高层次的类(如 JDK 核心库),子类加载器负责加载更具体的应用类(如用户代码)。它们通过双亲委派机制协作,确保类加载的唯一性和安全性。


关键区别

1. 加载范围

  • 父类加载器
  • 加载更通用、基础的类库。
  • 示例:
    • Bootstrap ClassLoader:加载 <JAVA_HOME>/lib(如 java.lang.Object)。
    • Extension ClassLoader:加载 <JAVA_HOME>/lib/ext
  • 子类加载器
  • 加载应用特定的类。
  • 示例:
    • Application ClassLoader:加载 classpath 中的类。
    • 自定义类加载器:加载特定路径或动态类。

2. 层级关系

  • 父类加载器
  • 位于加载器层次的上层,优先级高。
  • 是子类加载器的父节点。
  • 示例:Bootstrap 是 Ext 的父加载器,Ext 是 App 的父加载器。
  • 子类加载器
  • 位于加载器层次的下层,依赖父加载器。
  • 示例:AppClassLoader 的父加载器是 ExtClassLoader。

3. 职责分工

  • 父类加载器
  • 负责核心类和共享类的加载,保证一致性。
  • 示例:加载 String,避免重复定义。
  • 子类加载器
  • 负责加载用户代码或特定模块,灵活性更高。
  • 示例:加载 com.example.MyClass

4. 实现方式

  • 父类加载器
  • Bootstrap 用 C++ 实现,无 Java 对象(parent = null)。
  • ExtClassLoader 是 Java 类,继承 ClassLoader
  • 子类加载器
  • 通常是 Java 类(如 AppClassLoader 或自定义类加载器)。

5. 双亲委派中的作用

  • 父类加载器
  • 优先尝试加载,保护核心类。
  • 子类加载器
  • 父加载器失败后才加载,补充功能。

示例

  • 加载 java.lang.String
  • AppClassLoader(子) -> ExtClassLoader(父) -> BootstrapClassLoader(顶层父)。
  • Bootstrap 加载成功,返回。
  • 加载 com.example.MyClass
  • AppClassLoader(子) -> ExtClassLoader(父) -> BootstrapClassLoader。
  • 上层未找到,AppClassLoader 加载。
ClassLoader appLoader = ClassLoader.getSystemClassLoader(); // AppClassLoader
System.out.println(appLoader); // sun.misc.Launcher$AppClassLoader
System.out.println(appLoader.getParent()); // ExtClassLoader
System.out.println(appLoader.getParent().getParent()); // null (Bootstrap)

延伸与面试角度

  • 为什么分父子?
  • 安全性:父加载器优先加载核心类,防止篡改。
  • 复用性:父加载器加载的类全局共享。
  • 加载顺序
  • 双亲委派:父 -> 子。
  • 打破后:子 -> 父(如 Tomcat)。
  • 实际应用
  • :JDK 核心类(String)。
  • :Web 应用类(Servlet)。
  • 与命名空间
  • 不同加载器加载的类有独立命名空间。
  • 示例:App 和自定义加载器加载同名类,互不冲突。
  • 面试点
  • 问“父子职责”时,提范围和安全。
  • 问“打破场景”时,提 Tomcat 隔离。

总结

父类加载器加载核心类,层级高,优先级高;子类加载器加载应用类,层级低,依赖父加载器。区别在范围、层次和职责,双亲委派确保协作。面试时,可画加载器层次或提 getParent() 示例,展示理解深度。