对于泛型类型,主要要了解的是它们不是协变的。
因此,尽管您可以这样做:
final String string = "string";final Object object = string;
以下内容将无法编译:
final List<String> strings = ...final List<Object> objects = strings;
这是为了避免您绕过通用类型的情况:
final List<String> strings = ...final List<Object> objects = strings;objects.add(1);final String string = strings.get(0); <-- oops
因此,一一讲解您的示例
1个您的通用方法采用a
List<T>,而您采用
List<?>;(基本上是)
List<Object>。
T可以分配给
Object类型,并且编译器满意。2
您的通用方法相同,您传入
List<List<?>>。
T可以分配给
List<?>类型,编译器再次感到高兴。3
这与 2 基本上相同,但具有另一层嵌套。
T仍然是
List<?>类型。4
这是有点梨形的地方,也是我从上面提出的观点。
您的通用方法采用
List<List<T>>。您通过了
List<List<?>>。现在,由于通用类型不是协变的,
List<?>因此无法将其分配给
List<T>。
实际的编译器错误(Java 8)是:
必填:
java.util.List<java.util.List<T>>找到:java.util.List<java.util.List<?>>原因:无法推断类型变量T
(参数不匹配;java.util.List<java.util.List<?>>无法转换为java.util.List<java.util.List<T>>)
基本上,编译器告诉您,
T由于必须推断
List<T>外部列表中嵌套的类型,因此找不到分配的对象。
让我们更详细地看一下:
List<?>是
List的 一些未知类型 -它可以是一个
List<Integer>或一个
List<String>;
我们可以
get这样做
Object, 但是我们不能
add。因为否则我们会遇到我提到的协方差问题。
List<List<?>>是
List的
List一些未知类型的-
它可能是一个
List<List<Integer>>或一个
List<List<String>>。在情况 1中
,可以分配
T给通配符列表,
Object但不允许
add对通配符列表进行 *** 作。在第 4种 情况下,此 *** 作无法完成-
主要是因为没有通用的构造可以防止
add外部攻击
List。
如果在第二种情况下将编译器分配
T给
Object,则可能会出现如下所示的情况:
final List<List<Integer>> list = ...final List<List<?>> wildcard = list;wildcard.add(Arrays.asList("oops"));
因此,由于协方差,不可能安全地将a分配
List<List<Integer>>给 任何其他 泛型
List。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)