我有一个Foo<T extends Foo<T>>
抽象类。我想基于其父类存储其实现的实例,因此我将它们存储在映射中private static final Map<Class<? extends Foo<?>>, Foo<?>> FOOS = new HashMap<>();
要添加到此映射,使用父类调用方法,然后通过反射初始化它。
public static Foo<?> addFoo(Class<? extends Foo<?>> foo) throws InstantiationException, IllegalAccessException {
return Optional.ofNullable(Foo.FOOS.get(foo)).orElse(Optional.ofNullable(Foo.FOOS.put(foo, foo.newInstance())).orElse(Foo.FOOS.get(foo)));
}
但是这会在Eclipse中产生错误:The method orElse(Foo<capture#25-of ?>) in the type Optional<Foo<capture#25-of ?>> is not applicable for the arguments (Foo<capture#29-of ?>)
然而,这种功能相似的方法不会产生错误。
public static Foo<?> addFoo(Class<? extends Foo<?>> foo) throws InstantiationException, IllegalAccessException {
Optional<Foo<?>> possibleFoo = Optional.ofNullable(Foo.FOOS.get(foo));
if(possibleFoo.isPresent()) {
return possibleFoo.get();
}
//The set to possibeFoo with an Optional is not needed, but this is for demonstration purposes
possibleFoo = Optional.ofNullable(Foo.FOOS.put(foo, foo.newInstance()));
return Foo.FOOS.get(foo);
}
为什么第一个发出错误但第二个没有,即使它在功能上相似?
答案 0 :(得分:3)
这是一个产生同样问题的简单示例。
static void example(List<?> list1, List<?> list2) {
Optional.of(list1).orElse(list2); // compile error
}
这看起来应该有效。 Optional.of(list1)
是Optional<List<?>>
,因此方法orElse
应该适用?
这里的问题是抓取工作的方式。假设list1
是List<String>
。然后我们希望Optional.of(list1)
成为Optional<List<String>>
。另一方面,如果list1
为List<Integer>
,我们希望Optional.of(list1)
为Optional<List<Integer>>
。因此,编译器不会将Optional.of(list1)
的类型视为Optional<List<?>>
,而是将Optional<List<X>>
视为某种未知类型X
。
由于类型X
未知且list2
的项目类型未知,因此可能不匹配。
你可以通过告诉编译器确实希望类型为Optional<List<?>>
来解决这个问题:
Optional.<List<?>>of(list1).orElse(list2); // compiles fine.
你的例子基本相同。你可以像这样编译它。
return Optional.<Foo<?>>ofNullable(FOOS.get(foo))
.orElse(Optional.<Foo<?>>ofNullable(FOOS.put(foo, foo.newInstance()))
.orElse(FOOS.get(foo)));
一般来说,如果你在编写涉及通配符和泛型类型的长行代码时遇到问题,我认为将它分解成几行是个好主意,声明一些表达式的类型方式(就像你在第二个例子中所做的那样)。