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

时间:2011-03-29 23:09:37

标签: java reflection classloader

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

1 个答案:

答案 0 :(得分:6)

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

重要的部分是(the documentation for getProxyClass()):

  

所有接口类型必须通过指定的类加载器按名称可见。换一种说法,   对于类加载器cl和每个接口i,以下表达式必须为true:

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

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

如果null适用于您的情况,我认为您的接口也有null类加载器(引导加载程序) - 那么您使用哪个类加载器并不重要。如果你必须从你不知道的接口创建一个代理,只需要给出第一个接口的类加载器,并希望你的调用者不会做一些奇怪的事情。

为什么需要它?

你可以这样想象:

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

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

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