Java ClassLoader委托模型?

时间:2010-04-15 03:49:33

标签: java classloader

ClassLoader上调用loadClass()时,ClassLoader是否首先检查该类是否已加载,还是立即将此检查委派给其父ClassLoader

Java API说:

  

当请求查找类或资源时,ClassLoader实例会在尝试查找类或资源本身之前,将对类或资源的搜索委托给其父类加载器。

但是在 Java Reflection in Action 一书中有关于类加载器的特定章节,其中说:

  

类加载器调用findLoadedClass来检查类是否已经加载。如果类加载器没有找到加载的类,则在父类加载器上调用loadClass。

哪个是对的?

6 个答案:

答案 0 :(得分:17)

正确的类加载器实现将:

  1. 检查班级是否已加载。
  2. 通常要求父类加载器加载类
  3. 尝试在自己的类路径中找到该类。
  4. ClassLoader.loadClass的默认实现类似于:

    protected synchronized Class<?> loadClass(String name, boolean resolve) {
      // First, check if this class loader has directly defined the class or if the
      // JVM has initiated the class load with this class loader.
      Class<?> result = findLoadedClass(name);
      if (result == null) {
        try {
          // Next, delegate to the parent.
          result = getParent().loadClass(name);
        } catch (ClassNotFoundException ex) {
          // Finally, search locally if the parent could not find the class.
          result = findClass(ex);
        }
      }
      // As a remnant of J2SE 1.0.2, link the class if a subclass of the class
      // loader class requested it (the JVM never calls the method,
      // loadClass(String) passes false, and the protected access modifier prevents
      // callers from passing true).
      if (resolve) {
        resolveClass(result);
      }
      return result;
    }
    

    某些类加载器实现将委托给其他非父类加载器(OSGi,例如,根据包委托给类加载器的图形),并且一些类加载器实现将在委派之前在本地类路径中查找类

答案 1 :(得分:2)

Java API是正确的。

  

当要求找到一个班级或   资源,一个ClassLoader实例   委托搜索课程或   资源到其父类加载器   在尝试找到班级之前   资源本身。

来自Java Classloading Mechanism -

  

在加载类时,类加载器首先将对类的搜索“委托”到其父类加载器,然后再尝试查找类本身。

答案 2 :(得分:2)

这两个陈述并非完全相互排斥。如果父ClassLoader以前未能找到Class,则Class将仅存在于当前ClassLoader的已加载类集中。所以,

  

当要求查找(描述的外部数据)类或   资源,一个ClassLoader实例   委托搜索(描述的外部数据)类或   资源到其父类加载器   在尝试查找(描述的外部数据)类或   资源本身。

如果它知道它的父节点找不到类但它可以(如先前加载类所示)

,它不会阻止它发生短路

答案 3 :(得分:1)

这基本上是它的工作原理。你输入

Foo f = new Foo();

此时,类加载器将确定是否已加载Foo(),即它在memory / perm gen中的位。如果已加载,则使用它。否则将其委托给父类加载器以尝试解析该类。从磁盘读取该类的位,然后加载到内存中。在下一个new Foo(),现在可以在内存/已加载中找到该类。

答案 4 :(得分:0)

为了同意斯里兰卡的答案,它将始终委托给父母,而api是正确的。如果你正在玩类加载,这可能会让事情变得有点棘手,或者达到你想要的效果。我建议用最小的类路径启动jvm,然后使用自定义类加载器加载所有类,最简单的方法是使用URLClassloader或包装URLClassloader的复合对象,这样你就可以跟踪哪个类加载时和。

另外值得注意的是,如果C和D不是同一个类加载器 - 父子层次结构的一部分,则由类加载器C加载的类A!=由类加载器C加载的类A.

答案 5 :(得分:0)

在这种情况下还应该注意另外一个问题。 API文档说:

  

。的方法和构造   由类加载器创建的对象可以   参考其他课程。确定   提到的类,Java   虚拟机调用loadClass   类加载器的方法   最初创建了这个类。

意味着引用类的网络由同一个类加载器加载。