我应该向 Proxy.newProxyInstance(...) 提供哪个 ClassLoader?

2022-09-04 04:20:37

我已经阅读了文档,但我仍然不明白我应该提供哪个类加载器作为参数。我已经尝试了一些选项,但这似乎对编译或代理的行为没有影响。有点令人不安的是,我可以将任何内容作为类装入器参数传递,包括,并且代码仍然可以正常工作。任何人都可以解释这一点,并告诉我如果我为类加载器提供一个糟糕的参数,会出现什么样的错误?我应该补充一点,我对Java或一般的类装入器是什么没有一个强烈的直观概念。null


答案 1

任何类都需要有一个类加载器,因此我们必须在这里给出一个。

重要的部分是这样的(在getProxyClass()的文档中):

所有接口类型都必须通过指定的类装入器按名称可见。换句话说,对于类装入器 cl 和每个接口 i,以下表达式必须为 true:

Class.forName(i.getName(), false, cl) == i

因此,您可以使用任何类装入器,其中一个(或多个)父类装入器定义了给定的接口。

如果适用于您的情况,我想您的接口还具有类装入器(引导装入器) - 那么您使用哪个类装入器并不重要。如果你必须从你不知道的接口创建一个代理,只需采用给出的第一个接口的类加载器,并希望你的调用方没有做一些奇怪的事情。nullnull

为什么需要它?

你可以想象它是这样的:

  • 该方法为一个新类创建(如果它尚不存在)一些字节码,该类实现所有接口的所有方法(每个方法都只是将调用转发到您的)。getProxyClass()InvocationHandler
  • 然后,它将此字节码传递给您指定的类装入器的方法。defineClass
  • 在此字节码中,所有接口都按名称引用,VM 现在使用引用的调用来解析这些接口。forName

我们可以在没有任何VM魔力的纯Java中以这种方式实现它,但是我们需要为它创建一个新的类加载器(以指定的类加载器作为父级),而不是能够重用现有的类加载器。getProxyClass

实际上,这个合成类可能没有实际的字节码,因为VM能够在这里使用它的内部魔力:-)


答案 2