2013-10-18 65 views
3

我不確定這是否可以用Java,但我試圖實現一個在編譯時不可用的接口**並將它作爲一個對象傳遞給另一個類的界面。比方說,我有這樣的接口:Java反射:實現接口並傳遞給另一個類

public interface MyInterface { 
    void onReceive(int i); 
} 

和其他類,如:

public void MyClass { 
    ArrayList<MyInterface> listenerList = new ArrayList<MyInterface>(); 

    public void add(MyInterface m) { 
     listenerList.add(m); 
    } 
} 

如果他們可以在編譯的時候,我會用他們喜歡的:

blah = new MyInterface() { 
    public void onReceive(int i) { 
     System.out.println("BLAH"); 
    } 
} 

MyClass mc = new MyClass(); 
myClass.add(blah); 

我想知道是否有一種方法可以編寫與上面相同的代碼,前兩個類只在運行時纔可用。

提前致謝!

**我試圖從Android的ROM使用框架庫,但它是在達爾維克字節碼,所以我不能用它進行編譯。

UPDATE:下面是我用來測試溶液一些示例代碼:

文件A/IIMSListener.java

// Excerpt from decompiled class 

public interface IIMSListener 
{ 
    void onReceive(int p0, int p1/*, IMSParameter p2*/); 
} 

文件A/IMSRemoteListenerStub.java

// Excerpt from decompiled class 

import java.util.concurrent.*; 
import java.util.*; 

public class IMSRemoteListenerStub 
{ 
    public List<IIMSListener> mListenerList = new CopyOnWriteArrayList<IIMSListener>(); 

    public boolean addListener(final IIMSListener iimsListener) { 
     if (iimsListener != null && !this.mListenerList.contains(iimsListener)) { 
      this.mListenerList.add(iimsListener); 
      return true; 
     } 
     return false; 
    } 

    public boolean removeListener(final IIMSListener iimsListener) { 
     if (iimsListener != null && this.mListenerList.contains(iimsListener)) { 
      this.mListenerList.remove(iimsListener); 
      return true; 
     } 
     return false; 
    } 
} 

文件b/test.java

impor t java.lang.reflect。 ; import java.util。;

public class test { 
    public static void main(String[] args) throws IllegalAccessException, 
               IllegalArgumentException, 
               InvocationTargetException, 
               NoSuchMethodException, 
               SecurityException, 
               ClassNotFoundException { 

    // Implement interface 
    Class<?> IIMSListener = Class.forName("IIMSListener"); 

    Object listenerInstance = Proxy.newProxyInstance(IIMSListener.getClassLoader(), new Class<?>[]{IIMSListener}, new InvocationHandler() { 
     @Override 
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
     if(method.getName().equals("onReceive")){ 
      System.out.println("ARGS: " + (Integer)args[0] + ", " + (Integer)args[1]); 
      return 1; 
     } 
     else return -1; 
     } 
    }); 

    // Test 
    Method onReceive = listenerInstance.getClass().getDeclaredMethod("onReceive", new Class[] { int.class, int.class }); 
    onReceive.invoke(listenerInstance, new Object[] { 1, 2 }); 

    try { 
     // Pass to another class 
     Class IMSRemoteListenerStub = Class.forName("IMSRemoteListenerStub"); 
     Constructor ctor = IMSRemoteListenerStub.getConstructor(); 
     Object stubInstance = ctor.newInstance(new Object[] {}); 
     Method addListener = stubInstance.getClass().getDeclaredMethod("addListener", new Class[] { IIMSListener }); 
     addListener.invoke(stubInstance, new Object[] { listenerInstance }); 

     // Test 
     Field mListenerList = IMSRemoteListenerStub.getField("mListenerList"); 
     List<?> list = (List<?>)mListenerList.get(stubInstance); 
     onReceive.invoke(list.get(0), new Object[] { 3, 4 }); 
    } 
    catch (InstantiationException e) {} 
    catch (NoSuchFieldException e) {} 
    } 
} 

執行:

$ cd b 
$ CLASSPATH=".:../a" java test 
ARGS: 1, 2 
ARGS: 3, 4 
+0

難道永遠都會有相同的接口或接口會改變? –

+1

如果您在編譯時不知道類型,則必須使用反射來獲取構造函數和方法的列表。然後你需要找到解決任何參數的方法,以便調用任何方法或構造函數。總而言之,不是一個簡單的任務。 您可以使用JDK代理來使用'InvocationHandler'生成接口實例,但如果沒有該類型或反射的變量,它將不會很有用。 –

+0

@李光華英文名男子。 –

回答

6

如果將是相同的接口,然後使用Dynamic Proxies

//Loading the class at runtime 
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException { 
    Class<?> someInterface = Class.forName("SomeInterface"); 

    Object instance = Proxy.newProxyInstance(someInterface.getClassLoader(), new Class<?>[]{someInterface}, new InvocationHandler() { 

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

      //Handle the invocations 
      if(method.getName().equals("someMethod")){ 
       return 1; 
      } 
      else return -1; 
     } 
    }); 
    System.out.println(instance.getClass().getDeclaredMethod("someMethod", (Class<?>[])null).invoke(instance, new Object[]{})); 
} 
+0

感謝您的回答!界面從不改變。我想知道的一件事是:如果'SomeInterface'在編譯時不可用,那麼它如何被用作該行的類型:'SomeInterface instance = ...'? –

+0

@陳曉龍哦,是的,這是一個錯誤。我編輯了完全使用反射的答案。看一看。儘管如此。 –

+0

但只是一個普遍想知道你將如何插入你正在加載的類和你不知道的接口。我的意思是你將不得不一直使用反射。 –

相關問題