1

私はこの(簡略化された)Javaインターフェースを持っています

public interface MyInterface<T> {
    public String run( T arg );
}

およびそのインターフェースを実装するいくつかのクラス、つまり

public final class SomeImplementation1 implements MyInterface<String> {
   @Override
   public String run( String arg) {
       // do something with arg and return a string
   }
}

public final class SomeImplementation2 implements MyInterface<CustomClass> {
   @Override
   public String run( CustomClass arg) {
       // do something with arg and return a string
   }
}

これで、これらすべての実装用のグローバル リソース マネージャーができました。これは、後で使用するためにそれらすべてを List でインスタンス化します。私が達成したいのはこのようなもので、明らかにエラーが発生します

public final class MyInterfaceManager {
    private List<MyInterface<?>> elements = new List<MyInterface<?>>();

    public MyInterfaceManager() {
        elements.put( new SomeImplementation1() );
        elements.put( new SomeImplementation2() );
        // more implementations added
    }

    // this is what I would like to achieve
    public <T> void run( T arg ) {
        for( MyInterface<?> element: elements ) {
            String res = element.run( arg );    // ERROR
        }
    }
}

「メソッド呼び出し変換で arg を ? の capture#1 に変換できない」ためです。考えられる解決策は、ループ内でテストを実行しinstanceof、要素を引数とともに実際の型にキャストすることです。

    public <T> void run( T arg ) {
        for( MyInterface<T> element: elements ) {
            if (element instanceof SomeImplementation2) {
                String res = ((SomeImplementation2)element).run( (CustomClass)arg  );
            } else if // other tests here ...
        }
    }

しかし、私はそれが好きではありません。まったくエレガントではなく、多くのinstanceofキャストを行う必要があります。だから、これを達成するためのより良い方法があるかどうか疑問に思っています。ご協力いただきありがとうございます :)

4

1 に答える 1

1

タイプ eraseに遭遇しています。型パラメータに関連するインスタンスをinterface返す別のメソッドを に追加する必要があります。これにより、その上で実行時チェックを行うことができます。Class<T>Class

私はこれを次のように達成します:

public interface MyInterface<T> {
    String run( T arg );
    Class<T> type();
}

したがって、interfaceはその型を返します。注:すべてのinterfaceメンバーはpublicデフォルトであり、追加の必要はありませんpublic

public final class SomeImplementation1 implements MyInterface<String> {
   @Override
   public String run(final String arg) {
       return arg;
   }

   @Override
   public Class<String> type() {
       return String.class;
   } 
}

@SuppressWarnings({"unchecked"})
public static  <T> String run(final T arg) {
    for (final MyInterface<?> element : elements) {
        if (element.type().isAssignableFrom(arg.getClass())) {
            return ((MyInterface<T>) element).run(arg);
        }
    }
    throw new IllegalArgumentException("No element found.");
}

ロジックは、MyInterface提供された引数がその に安全にキャスト可能かどうかをそれぞれチェックすることMyInterfaceですtype()。そうであれば、全体MyInterfaceargの型にキャストできます。コンパイラはコンパイル時にこれを確認できないため、これはチェックされていませんが、手動でチェックを行っているため、この警告は無視できます。

public static void main(String[] args) throws Exception {
    elements = new LinkedList<>();
    elements.add(new SomeImplementation1());

    System.out.println(run("test"));
    System.out.println(run(1));
}

出力:

test
Exception in thread "main" java.lang.IllegalArgumentException: No element found.
    at com.XXX.App.run(App.java:33)
    at com.XXX.App.main(App.java:55)

予想通り。

于 2013-09-26T11:46:23.270 に答える