java - UrlClassLoader 委托(delegate)和继承层次

标签 java classloader

我对 UrlClassLoader 委托(delegate)层次结构和继承层次结构感到困惑。 我创建了扩展 UrlClassLoader 的类并执行了:childOfUrlClassLoader.getParent().getClass().getName() 这给了我: sun.misc.Launcher$AppClassLoader。 之后我访问了上面提到的类(source)

249 static class AppClassLoader extends URLClassLoader {
        //...
308     protected synchronized Class<?> loadClass(String name, boolean resolve)
309         throws ClassNotFoundException
310     {
311         // First, check if the class has already been loaded
312         Class c = findLoadedClass(name);
313         if (c == null) {
314             try {
315                 if (parent != null) {
316                     c = parent.loadClass(name, false);
317      
          // ...
329         return c;
330     }

然后我检查了谁是 AppClassLoader 的父级。预计我得到了 sun.misc.Launcher$ExtClassLoader 并且 ExtClassLoader 的父级是 null


我有几个问题:

1) 因为 AppClassLoader.loadClass 的代码有行,谁来加载我的类

294    return (super.loadClass(name, resolve));

它看起来像循环,不是吗?

2) 为什么 ExtClassLoader 没有 BootstrapClassLoader 作为父级,而是有 null

3) AppClassLoader 类扩展 UrlClassLoader 的目的是什么?

最佳答案

委托(delegate)优先模型

内置的 java 类加载器遵循委托(delegate)优先模型。这意味着 ClassLoader 将允许其父类在尝试自己加载类之前加载它。加载器的层次结构在顶部是引导加载器,然后是扩展类加载器,即应用程序类加载器。在应用程序类加载器下可以找到 URLClassLoaders 和应用程序创建的任何其他加载器。

引导类加载器可以从 rt.jar 加载文件,其中包含最重要的 java 类,包括 java.lang、java.io、java.util 和 java.net 包中的类。扩展类加载器从 java 安装中的其他 jar 文件加载类。应用程序类加载器加载在类路径中找到的类,并且是应用程序启动时的当前类加载器。

正在加载

那么当应用程序想要加载一个 HashMap 时会发生什么?当前的类加载器被要求加载 HashMap 类。在尝试任何事情之前,它会询问其父类,即扩展类加载器来加载该类。反过来,扩展类加载器委托(delegate)给引导类加载器,引导类加载器在 rt.jar 中找到类并加载它。

如果要加载的类在类路径中,请求将像以前一样转到引导类加载器以检查 rt.jar。引导加载程序找不到该类,因此该任务被返回到扩展类加载器,该扩展类加载器在 java 安装中搜索该类。当这失败时,任务恢复到扫描类路径的应用程序类加载器。

类加载器缓存

在实践中,每个类加载器都有一个缓存,其中存储了已加载的类,并且在委托(delegate)给父级之前搜索缓存,但这不会改变先委托(delegate)的原则。

这里是检查缓存的地方

Class c = findLoadedClass(name);

URLClassLoaders

应用程序创建的 URLClassLoader 将应用程序 ClassLoader 作为父级。如果它遵循委托(delegate)优先模型,将在提供的 URL 之前的类路径中找到类。

问题

1) 谁加载我的类

我在您的链接中看到略有不同的代码

309         // First, check if the class has already been loaded
310         Class c = findLoadedClass(name);
311         if (c == null) {
312             try {
313                 if (parent != null) {
314                     c = parent.loadClass(name, false);
315                 } else {
316                     c = findBootstrapClass0(name);
317                 }
318             } catch (ClassNotFoundException e) {
319                 // If still not found, then invoke findClass in order
320                 // to find the class.
321                 c = findClass(name);
322             }
323         }

如果一个类没有被父类加载,它会抛出一个 ClassNotFoundException 被捕获并允许当前的 ClassLoader 找到这个类

321                 c = findClass(name);

2) 为什么 ExtClassLoader 没有 BootstrapClassLoader 作为父级,而是有 null?

这由 getClassLoader API 回答

[getClassLoader()] returns the class loader for the class. Some implementations may use null to represent the bootstrap class loader.

3) AppClassLoader 类扩展 UrlClassLoader 的目的是什么?

考虑到应用程序类加载器并不特殊,因为它加载的是用户提供的类,而不是系统类。类路径实际上是一个 URI 列表,因此 URLClassLoader 是一个合适的父类(super class)。

引用资料

有很多关于类加载的文章,包括

关于java - UrlClassLoader 委托(delegate)和继承层次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34160415/

相关文章:

java - Ubuntu命令行./idea.sh可以启动idea,但是桌面图标点击找不到JDK

java - 如何在单个顶点上绘制具有多条边的图(例如允许循环)?

XP 和 Vista/Windows 7 之间的 Java WebStart 权限差异

java - 用Java创建一个漂亮的 ListView

java - 在不影响现有系统的情况下更新新的 Java 库

java - 设置类加载器不同的目录

java - JSF-Spring集成应用中如何开启CSRF保护

java - 检测Java类是否可加载

android - dalvik.system.PathClassLoader 不加载多个 JAR

java - 为什么 JVM 会在每次实例化时一次又一次地加载相同的 (GUI) 类?