I have read the documentation, but I still don't understand which classloader I should supply as an argument. I've tried a few options, but this seems to have no effect on compilation or the behavior of the proxy. It is a little unsettling that I can pass anything as the class loader argument, including null
, and the code still works fine. Can anyone explain this, and tell me what kind of errors can arise if I provide a bad argument for the classloader? I should add that I don't really have a strong intuitive idea of what a classloader is, in Java or in general.
问题:
回答1:
Any class needs to have a classloader, thus we have to give one here.
The important part is this (in the documentation for getProxyClass()
):
All of the interface types must be visible by name through the specified class loader. In other words, for class loader cl and every interface i, the following expression must be true:
Class.forName(i.getName(), false, cl) == i
So, you can use any classloader where one (or more) of its parent classloaders defined the given interfaces.
If null
works in your case, I suppose your interfaces have also the null
class loader (the bootstrap loader) - then it should not matter which classloader you used. If you have to create an proxy from interfaces you don't know, simply take the classloader of the first interface given and hope your caller did not do something strange.
Why it is needed?
You can imagine it like this:
- The
getProxyClass()
method creates (if it does not exist yet) some bytecode for a new class implementing all the methods of all your interface (each of them simply forwarding the call to yourInvocationHandler
). - It then passes this bytecode to the
defineClass
method of the classloader you specified. - In this bytecode, all of your interfaces are referenced by name, and the VM now uses the cited
forName
call to resolve these interfaces.
We could have implemented this getProxyClass
this way in pure Java without any VM magic, but we would need to create a new classloader (with the specified one as a parent) for it instead of being able to reuse an existing one.
In reality there might not be an actual bytecode for this synthetic class, since the VM is able to use its internal magic here :-)