Java动态适配器

发布于 2024-11-17 02:21:57 字数 532 浏览 3 评论 0原文

我正在使用一些生成以下接口的 Java 代码。此代码不可修改。

interface A1 {
    public void run();
}

interface A2 {
    public void run();
}

...

interface A24 {
    public void run();
}

我在以下代码中遇到类转换错误。我将如何动态构建我的界面的适配器?

interface ARunnable {
    public void run();
}

public void someMethod() {
    // getARunnables() returns a list of A1, A2, ... A24
    List<ARunnable> runnables = (List<ARunnable>)getARunnables(); 

    for (ARunnable a : runnables) {
        a.run();
    }
}

I'm using some Java code which produces the following interfaces. This code is non-modifiable.

interface A1 {
    public void run();
}

interface A2 {
    public void run();
}

...

interface A24 {
    public void run();
}

I'm having a class cast error with the following code. How would I dynamically build an adapter to my interface?

interface ARunnable {
    public void run();
}

public void someMethod() {
    // getARunnables() returns a list of A1, A2, ... A24
    List<ARunnable> runnables = (List<ARunnable>)getARunnables(); 

    for (ARunnable a : runnables) {
        a.run();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

你对谁都笑 2024-11-24 02:21:57

由于无法修改接口来扩展 java.lang.Runnable,因此一种选择是使用 java.lang.reflect.Proxy 来构建委托给 A1、A2... 接口的 Runnable 实例。

这并不简单,但请看一下使用 java.lang.reflect.Proxy 的示例。该示例只是根据方法名称委托给委托对象。

public class ProxyTest
{
    public static void main(String... args)
    {
        List<?> instances = Arrays.asList(new A1());
        List<ARunnable> runnableInstances = new ArrayList<ARunnable>(instances.size());
        for (Object instance : instances)
        {
            ARunnable runnableInstance = (ARunnable)Proxy.newProxyInstance(
                                            ARunnable.class.getClassLoader(), 
                                            new Class<?>[] {ARunnable.class}, 
                                            new RunnableWrapper(instance));
            runnableInstances.add(runnableInstance);
        }

        //Now we have a list of ARunnables!
        //Use them for something
        for (ARunnable runnableInstance : runnableInstances)
        {
            runnableInstance.run();
        }
    }

    private static class RunnableWrapper implements InvocationHandler
    {
        private final Object instance;

        public RunnableWrapper(Object instance)
        {
            this.instance = instance;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable
        {
            //Ensure that your methods match exactly or you'll get NoSuchMethodExceptions here
            Method delegateMethod = instance.getClass().getMethod(method.getName(), method.getParameterTypes());
            return(delegateMethod.invoke(instance, args));
        }
    }

    public static class A1
    {
        public void run()
        {
            System.out.println("Something");
        }
    }

    public static interface ARunnable
    {
        public void run();
    }
}

另外,我建议您修复

List<ARunnable> runnables = (List<ARunnable>)getARunnables(); 

您不应忽略的“类型安全警告”行。该对象列表实际上并不包含 ARunnables,因此会出现 ClassCastException。

Since the interfaces can't be modified to extend java.lang.Runnable, an option would be to use java.lang.reflect.Proxy to build up instances of Runnable that delegate to your A1, A2... interfaces.

It's not trivial, but take a look at this example using java.lang.reflect.Proxy. The sample simply delegates to a delegate object based on method name.

public class ProxyTest
{
    public static void main(String... args)
    {
        List<?> instances = Arrays.asList(new A1());
        List<ARunnable> runnableInstances = new ArrayList<ARunnable>(instances.size());
        for (Object instance : instances)
        {
            ARunnable runnableInstance = (ARunnable)Proxy.newProxyInstance(
                                            ARunnable.class.getClassLoader(), 
                                            new Class<?>[] {ARunnable.class}, 
                                            new RunnableWrapper(instance));
            runnableInstances.add(runnableInstance);
        }

        //Now we have a list of ARunnables!
        //Use them for something
        for (ARunnable runnableInstance : runnableInstances)
        {
            runnableInstance.run();
        }
    }

    private static class RunnableWrapper implements InvocationHandler
    {
        private final Object instance;

        public RunnableWrapper(Object instance)
        {
            this.instance = instance;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable
        {
            //Ensure that your methods match exactly or you'll get NoSuchMethodExceptions here
            Method delegateMethod = instance.getClass().getMethod(method.getName(), method.getParameterTypes());
            return(delegateMethod.invoke(instance, args));
        }
    }

    public static class A1
    {
        public void run()
        {
            System.out.println("Something");
        }
    }

    public static interface ARunnable
    {
        public void run();
    }
}

Also I would recommend you fix the line

List<ARunnable> runnables = (List<ARunnable>)getARunnables(); 

That type safety warning you should not ignore. That list of objects does not actually contain ARunnables, hence the ClassCastException.

初见 2024-11-24 02:21:57

考虑此示例代码(为简单起见,没有循环):

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

    public class Main {

      interface Interface {
        public void run();
      }

      static class Hello /* does't implement Interface */{

        public void run() {
          System.out.println("Hello, world!!");
        }
      }

      static <T> T dirtyCast(Class<T> intrface, final Object target) {

        return intrface.cast(Proxy.newProxyInstance(
          intrface.getClassLoader(),
          new Class<?>[] { intrface }, new InvocationHandler() {

          @Override
          public Object invoke(Object proxy, Method method,
            Object[] args) throws Throwable {

              Method targetMethod = target.getClass().getMethod(
                method.getName(), method.getParameterTypes());

              return targetMethod.invoke(target, args);
          }

        }));
      }

      public static void main(String[] args) {

        Interface proxy = dirtyCast(Interface.class, new Hello());

        proxy.run();

      }
    }

如果您想传递参数或返回值或引发异常,请不要认为此解决方案可行。问题在于共享对象(作为参数、返回值和异常)需要位于同一个(公共)类加载器中。这也意味着通常的 java lang 类型和异常都可以。

您还必须牢记安全考虑。类加载器可能有不同的(不兼容的)安全约束。

如果您很快遇到麻烦,我会尝试为此设计的项目,例如 transloader

玩得开心。

Consider this sample code (doesn't have the loop for simplicity):

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

    public class Main {

      interface Interface {
        public void run();
      }

      static class Hello /* does't implement Interface */{

        public void run() {
          System.out.println("Hello, world!!");
        }
      }

      static <T> T dirtyCast(Class<T> intrface, final Object target) {

        return intrface.cast(Proxy.newProxyInstance(
          intrface.getClassLoader(),
          new Class<?>[] { intrface }, new InvocationHandler() {

          @Override
          public Object invoke(Object proxy, Method method,
            Object[] args) throws Throwable {

              Method targetMethod = target.getClass().getMethod(
                method.getName(), method.getParameterTypes());

              return targetMethod.invoke(target, args);
          }

        }));
      }

      public static void main(String[] args) {

        Interface proxy = dirtyCast(Interface.class, new Hello());

        proxy.run();

      }
    }

Please don't consider this solution as feasible if you want to pass arguments or return values or throw exceptions. The problem is that the shared objects (as arguments and return values and exceptions) need to live in the same (common) classloader. This also means that usual java lang types and exceptions will be okay.

Also you have to bear in mind security considerations. Classloaders may have different (incompatible) security constraints.

If you run quickly into trouble, I would try a project designed for this like transloader.

Have fun.

掀纱窥君容 2024-11-24 02:21:57

根据您的情况,您可以简单地使用

public void someMethod() throws ReflectiveOperationException {
    // getARunnables() returns a list of A1, A2, ... A24
    List runnables = (List)getARunnables(); 

    for (Object r : runnables) {
        r.getClass().getMethod("run").invoke(r);
    }
}

In your case you can use simply

public void someMethod() throws ReflectiveOperationException {
    // getARunnables() returns a list of A1, A2, ... A24
    List runnables = (List)getARunnables(); 

    for (Object r : runnables) {
        r.getClass().getMethod("run").invoke(r);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文