如何实现在编译时不可用的接口

时间:2017-09-14 04:29:39

标签: java reflection

使用反射,可以实现对编译时不可用的类方法的调用。这是使框架代码可以使用不同库版本的有效方法。

现在,说有一个界面

javassist

我的代码还不知道这个接口,但是我想准备一个实现,这个接口可能由未来的库版本提供,它需要使用这个接口的实现。我想避免java.lang.reflect.Proxy.newProxyInstance。我认为应该有一种使用{ "companyId":3, "name":"Third", "description":null, "characters":[{ "characterId":3, "name":"Third", "description":null, "status":null, "companyId":3, "userId":null }] } 的方式,但我还没弄清楚,如何有效地做到这一点。

1 个答案:

答案 0 :(得分:1)

首先,你需要以某种方式检索界面。然后使用newProxyInstance创建代理。最后,您可以在接口上调用方法或将代理发布到某个服务定位器或类似的。

Class<?> unknownInterface = ClassLoader.getSystemClassLoader().loadClass("bar.UnknownInterface");

Object proxy = Proxy.newProxyInstance(unknownInterface.getClassLoader(),
                                      new Class[] { unknownInterface },
                                      new Handler());

unknownInterface.getMethod("someMethod", String.class).invoke(proxy, "hello");
// other way to call it:
// ((UnknownInterface) proxy).someMethod("hello");

Handler类表示您要提供的实现:

public class Handler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("someMethod")) {
            System.out.println("this is the business logic of `someMethod`");
            System.out.println("argument: " + args[0]);
            return null;
        }
        return null;
    }
}

这里有什么缺点:

  • 您需要检索界面的Class对象。可能你需要它的名字。
  • a)您需要知道方法的名称和参数
  • b)或者,如果您知道方法的参数类型,您可以按类型匹配它们并忽略名称,例如args.length == 1 && args[0].getClass == String.class

基于this tutorial about proxies