为什么 A.class.getClassLoader() 没有 return loader.loadClass("A") 使用的加载程序

Why A.class.getClassLoader() does not return the loader used by loader.loadClass("A")

在这个测试用例中,我们通过特定的 class 加载器实例加载 class A,即 GwClassLoader。但是,A.class.getClassLoader() 不检索那个 class 加载程序?这是测试用例:

class A{
  static {
    ClassLoader loader = A.class.getClassLoader();
    System.out.println("A.<cinit>: " + loader);
  }
}

class ClassLoaderGw extends ClassLoader { }

public class App {
  public static void main(String [] args)  throws ClassNotFoundException,  InstantiationException,  IllegalAccessException {
    ClassLoaderGw loader = new ClassLoaderGw();
    System.out.println("Main: " + loader);
    Class<?> klass = loader.loadClass("A");
    Object obj = klass.newInstance();
  }
}

而且,这是 运行 class App 的输出:

Main: ClassLoaderGw@6d06d69c
A.<cinit>: sun.misc.Launcher$AppClassLoader@73d16e93

如何在 class A 的静态构造函数中获取 GwClassLoader 的实例?

这在the Javadoc中有描述:

Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:

  • Invoke findLoadedClass(String) to check if the class has already been loaded.
  • Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
  • Invoke the findClass(String) method to find the class.

您的 ClassLoadersun.misc.Launcher$AppClassLoader1 作为父级,因为如 default constructor 的 Javadoc 中所述(它在 ClassLoaderGw class, 因为没有明确的构造函数):

Creates a new class loader using the ClassLoader returned by the method getSystemClassLoader() as the parent class loader.

ClassLoaderGw 只是扩展了 ClassLoader 而没有覆盖任何方法。因此,它将遵循标准 loadClass 方法 (javadoc) 的策略......即首先委托给父 classloader。

在这种情况下,您的 A class 在父 classloader 的 class 路径上,所以 that 是什么会加载它。

拼图的最后一块是 getClassLoader() returns classloader 实际上 加载了 class,不是您要求进行加载的 classloader。


How can I get the instance of GwClassLoader inside the static constructor of the class A?

基本上,您不能...除非 GwClassloader 负责加载 class A

你能让它工作吗?嗯...如果您使用不同的 class 加载策略,您可以。可能是。如果 GwClassloader 能够找到 A 的字节码并调用 defineClass 本身,那么它将成为 A 的 class 加载器。

但是,您需要担心 class A 也可能被父 classloader 加载的可能性。如果发生这种情况,您可能同时存在两种不同的 A 类型。这可能会导致 class 在意想不到的地方出现异常。