我有这个(简化的)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
和演员。
所以,我想知道是否有更好的方法来实现这一目标。
谢谢你的帮助:)
答案 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));
}
正如所料。