7

これが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);

最初の 2 つのクラスが実行時にしか利用できない場合、上記と同じことを行うコードを記述する方法があるかどうか疑問に思っています。

前もって感謝します!

**Android の ROM からフレームワーク ライブラリを使用しようとしていますが、それは dalvik バイトコードであるため、コンパイルには使用できません。

更新: ソリューションをテストするために使用したサンプル コードを次に示します。

ファイル 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

java.lang.reflect をインポートします。; 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
4

1 に答える 1

10

同じインターフェイスになる場合は、動的プロキシを使用します

//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[]{}));
}
于 2013-10-18T01:43:54.627 に答える