父类加载器和子类加载器有什么区别
在 Java 的类加载体系中,父类加载器 和 子类加载器 的区别主要体现在 加载范围、层级关系 和 职责分工 上。父类加载器负责加载更核心、更高层次的类(如 JDK 核心库),子类加载器负责加载更具体的应用类(如用户代码)。它们通过双亲委派机制协作,确保类加载的唯一性和安全性。
关键区别
1. 加载范围
- 父类加载器:
- 加载更通用、基础的类库。
- 示例:
- Bootstrap ClassLoader:加载
<JAVA_HOME>/lib
(如java.lang.Object
)。 - Extension ClassLoader:加载
<JAVA_HOME>/lib/ext
。
- Bootstrap ClassLoader:加载
- 子类加载器:
- 加载应用特定的类。
- 示例:
- Application ClassLoader:加载
classpath
中的类。 - 自定义类加载器:加载特定路径或动态类。
- Application ClassLoader:加载
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()
示例,展示理解深度。