开发者

In Java, is there a way load class implementing interface that does not exist?

开发者 https://www.devze.com 2023-04-04 00:31 出处:网络
I\'ve seen Java doing a lot of magic, but is it possible to do this: At runtime, using (for example) ClassLoader.defineClass, load class A that implements interface B. The interface B does not actual

I've seen Java doing a lot of magic, but is it possible to do this:

At runtime, using (for example) ClassLoader.defineClass, load class A that implements interface B. The interface B does not actually exist in class path. Java will throw an exception (ClassNotFoundException IIRC) and the class won't be loaded. All other parts of class A are OK, and I know for a fact that no other part of progra开发者_StackOverflow中文版m will be using interface B. So, what I want to do is to make the interpreter ignore the missing interface definition and load a class that is completely the same as A except that is does not implement the interface B.

Is this possible? It of course could be achieved by catching the exception and manually editing the binary data of class A, then loading it again. Or by creating a dummy empty interface named B at runtime by manually constructing the B.class file and then loading it. But it seems a bit messy, so my question is, does Java provide any convenient ways to do this?

If not, I guess, I'll try implementing one of those two methods, but I still want to hear an opinion.

I'm doing this to provide a convenient way for two different code bases to interact with each other if they both are loaded, and to just work fine if only one of them is.


I'm not aware of any non-messy solutions to this that work similarly to what you're describing. It all boils down to a custom ClassLoader. Custom ClassLoaders are kind-of hard to begin with and if they have very specific semantics like this, then they become very ugly.

Not to mention the types of problems that you'll run into if your code suddenly doesn't run inside that ClassLoader.

I think the sane solution to this is to produce a mylibrary.jar and a mylibrary-noB.jar (or even more explicit: mylibrary-withB.jar and mylibrary-noB.jar) and let the users just select which one they want.


It is fairly common to include a second jar with the additional interfaces. The second jar can be included if needed and dropped if not. If its added to the end of the class path, this will happen implicitly.


Ultimately, the code in the classpath entry where interface B is defined has to use the same class as the code in the classpath entry where class A is defined. So defining a dummy interface will not work.

In Java you can dynamically implement an interface with a Proxy:

http://download.oracle.com/javase/6/docs/api/java/lang/reflect/Proxy.html

So at a later point in time, when your interface A is available, you can get it by reflection and create Proxy that implements its methods. The following example shows this with the java.lang.Runnable interface as interface A:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {

    public static void main(String[] args) throws Exception {
        Class interfaceClass = Class.forName("java.lang.Runnable");

        Object implementingRunnable = Proxy.newProxyInstance(
                    ProxyTest.class.getClassLoader(),
                    new Class[] {interfaceClass},
                    new MyInvocationHandler()
        );

        ((Runnable)implementingRunnable).run();


    }

    static class MyInvocationHandler implements InvocationHandler {

        public Object invoke(Object proxy, Method m, Object[] args)
                throws Throwable {
            System.out.println("called " + m);
            return null;
        }
    }
}

Of course at some point you have to actually cast the proxy to the interface A. You would have to do this in a class that is defined in the same class path entry as the interface.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号