当涉及类型参数时,无法将列表<List <?>>分配给List <List <?>>

Feu*_*mel 12 java generics

在下面的代码中,get()调用它并将结果分配给类型为的变量List<List<?>>.get()返回a List<List<T>>并在类型参数T设置为的实例上调用?,因此它应该适合.

import java.util.List;

class Test {
    void foo(NestedListProducer<?> test) {
        List<List<?>> a = test.get();
    }

    interface NestedListProducer<T> {
        List<List<T>> get();
    }
}
Run Code Online (Sandbox Code Playgroud)

但IntelliJ IDEA和Oracle的javac1.7.0_45版都拒绝我的代码无效.这是'javac'的错误消息:

java: incompatible types
  required: java.util.List<java.util.List<?>>
  found:    java.util.List<java.util.List<capture#1 of ?>>
Run Code Online (Sandbox Code Playgroud)

为什么这段代码无效,即如果允许则会出错?

rge*_*man 7

?是一个任何类型的通配符.一个?不能与另一个相同?,因为另一个?可能是任何其他类型,并且它们不匹配.您必须使用泛型来表示类型是相同的:

// Make this generic
<A> void foo(NestedListProducer<A> test) {
    List<List<A>> a = test.get();
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么会这样呢:`void foo(List <List <?>> arg){List <List <?>> a = arg; }`?什么会接受我的问题中的代码允许打破类型系统? (3认同)

jac*_*obm 4

List<List<T>>List<T>表示您可以从中读取或写入新的列表List<T>,并且类似地表示您可以从中读取或写入新的List<List<?>>列表。奇怪的是你可以将任何类型的列表转换为. 例如你可以写:List<?>List<T>?SList<?>

void foo(List<String> a, List<Integer> b, List<List<?>> out) {
  List<?> unknownA = a;
  List<?> unknownB = b;
  out.add(a);
  out.add(b);
}
Run Code Online (Sandbox Code Playgroud)

如果您可以将 a 转换List<List<T>>为 a List<List<?>>,则可以foo使用 a 进行调用List<List<PeanutButter>>,然后向其中添加字符串和整数列表。

一般来说,人们遇到这种情况是因为他们试图表达这样的概念:他们想要一个类型无关紧要的子集合的集合。如果这就是您想要的,您可以将类型从 更改List<List<?>>List<? extends List<?>>,它表达了我可以读取但不能写入的子列表列表的概念。List<List<T>>将 a 转换为 a是合法的List<? extends List<?>>