2011-06-24 24 views
1

我正在使用一些生成以下接口的Java代碼。這段代碼是不可修改的。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(); 
    } 
} 
+0

你有一個ClassCastException,因爲接口和類居住在不同的類加載器,對吧? – mschonaker

+0

這些接口中的每一個A1-> An是否有共同的接口?例如: 接口A1擴展ARunnable {} –

+0

埃米爾:不,他們不要 –

回答

1

由於接口不能修改,延長了java.lang.Runnable,一種選擇是使用java.lang.reflect.Proxy來的運行實例建立該委託給你的A1,A2。 ..接口。

這不是微不足道的,但使用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。

+0

謝謝!像魅力一樣工作 –

0

考慮此示例代碼(不具有簡單的循環):

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

玩得開心。