执行特定的参数化类方法

时间:2013-09-25 22:47:33

标签: java generics methods

我有这个(简化的)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无法通过方法调用转换转换为捕获?#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和演员。 所以,我想知道是否有更好的方法来实现这一目标。 谢谢你的帮助:)

1 个答案:

答案 0 :(得分:1)

您正在遇到type erasure。您需要向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的{​​{1}}。如果是,那么您可以将整个type()转换为MyInterface的类型。这是未选中的,因为编译器无法将其验证为编译时间,但是当您手动执行检查时,可以忽略此警告。

arg

输出:

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));
}

正如所料。