在嵌套泛型类型上使用通配符,如CompletableFuture <list <? extends =“”something =“”>&gt;

时间:2017-04-10 20:56:18

标签: java generics

这有效(编译并运行没问题):

List<? extends CharSequence> strings = null;
List<CharSequence> realStrings = new ArrayList<>();
strings = realStrings;

但是这段代码非常相似:

CompletableFuture<List<? extends CharSequence>> strings = null;
CompletableFuture<List<CharSequence>> realStrings = 
   CompletableFuture.completedFuture(new ArrayList<>());
strings = realStrings; // <--- ERROR

我到达的错误是Type mismatch: cannot convert from CompletableFuture<List<CharSequence>> to CompletableFuture<List<? extends CharSequence>>

这对我来说没什么意义。为什么在第一个例子中将'realStrings'分配给'字符串'而不是第二个呢?

PS:如果重要的话。使用Java 8进行编译。

2 个答案:

答案 0 :(得分:4)

泛型是不变的。这意味着,如果您声明类型CompletableFuture<List<? extends CharSequence>>,则只有在其类型参数与完全匹配时才能为其指定另一个CompletableFuture

可以使用有界通配符更改此行为,就像您在第一个代码段中显示的那样。您可以将List<CharSequence>分配给List<? extends CharSequence>

您必须使用CompletableFuture复制该内容。即您可以将CompletableFuture<T>分配给CompletableFuture<? extends T>。如果T = List<CharSequence>,那么您将获得CompletableFuture<? extends List<CharSequence>>。但由于在这种情况下List也是通用类型,您可以再次应用通配符来获取CompletableFuture<? extends List<? extends CharSequence>>

CompletableFuture<? extends List<? extends CharSequence>> strings = null;
CompletableFuture<List<CharSequence>> realStrings = 
    CompletableFuture.completedFuture(new ArrayList<>());
strings = realStrings; // <--- WORKS!

答案 1 :(得分:2)

答案有点难以解决问题,但基本上它与是否允许通过引用执行的任何操作都不能与提供的实例无关。

看一般问题,如果我有一个班级

class Foo<T> {
    public T getT() { /* ... */ }
    public void setT(T t) { /* ... */ }
}

然后我说

Foo<List<? extends Bar>> myFoo;

任何拥有此引用的人都必须能够执行操作

List<? extends Bar> myList = myFoo.getT();

List<? extends Bar> myList;
myFoo.setT(myList);

现在可以Foo<List<Bar>>支持吗?嗯......不。允许Foo<List<Bar>>知道setT List<Bar>收到的List<? extends Bar>List不同。当您将setT传递给Bar时,它可以将List传递给.add()&#39; List;但如果List<Frob>Frob(其中Bar延伸List<Frob>,那么List<? extends Bar>是有效的List<B>),那么它就赢了#39}能够处理它。

这就是为什么你的第二个代码片段无法正常工作的原因。为什么它不适用于第一个?那么,分析是不同的。在第一种情况下,List<? extends B> org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in ServletContext resource [/WEB- INF/beans.xml]: Cannot resolve reference to bean 'entityManagerFactory' while setting bean property 'entityManagerFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in ServletContext resource [/WEB-INF/beans.xml]: Invocation of init method failed; nested exceptionn is java.lang.IllegalArgumentException: No persistence unit with name 'spring- jpa-test' found

的一个例子,这是完全正确的。