Java ClassLoader委托模型?

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

Java API说:

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

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

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

哪个是对的?

适当的类加载器实现将:

  1. 检查该类是否已加载。
  2. 通常要求父类加载器加载该类
  3. 尝试在自己的类路径中找到该类。

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,例如,根据包委托给类加载器的图形),并且一些类加载器实现将在委托之前在本地类路径中查找类。

Java API是正确的。

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

从Java类加载机制 –

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

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

当请求查找(描述)类或资源的外部数据时,ClassLoader实例将在尝试查找之前将对类(或外部数据描述)类或资源的搜索委托给其父类加载器(描述的外部数据) )类或资源本身。

如果它知道它的父节点找不到类但它可以(如先前加载类所示),这不会阻止它短路

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

 Foo f = new Foo(); 

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

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

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

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

由类加载器创建的对象的方法和构造函数可以引用其他类。 要确定所引用的类,Java虚拟机将调用最初创建该类的类加载器的loadClass方法。

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