为什么一个包含泛型类型的泛型类型不能分配给通配符类型的泛型类

9
抱歉,如果标题看起来有点混乱,但是需要一些例子。
假设我有一个带有泛型类型参数的Java类:
public class GenericClass<T> {
}

我可以创建一个变量并指定它的类型为Object,同时将泛型参数设置为String。Java也允许我将这个变量赋值给另一个泛型参数为通配符<?>类型的变量:

GenericClass<String> stringy = ...
GenericClass<?> generic = stringy; // OK

然而,当使用带有泛型参数的类时,如果将该参数的类型设置为泛型,则不能将该类的对象分配给内部/嵌套参数为通配符类型 <?> 的完全相同类型/泛型化类型:

GenericClass<GenericClass<String>> stringy = ...
GenericClass<GenericClass<?>> generic = stringy; // Compile Error

// And just in case that is confusing, a more
// realistic example involving Collections:
List<GenericClass<String>> stringy = ...
List<GenericClass<?>> generic = stringy; // Compile Error

具体的编译错误如下:
Type mismatch: cannot convert from List<GenericClass<String>> to List<GenericClass<?>>

直觉上,我认为这个任务不应该成为一个问题。那么为什么这个任务会成为一个问题呢?


带通配符的嵌套泛型 - Dirk
2个回答

9
你面临的问题被称为“协变性”(Covariance),这与IT技术有关。请参考协变性和逆变性(计算机科学)
List<GenericClass<String>> stringy = ...
List<GenericClass<?>> generic = stringy;
generic.add(new GenericClass<Integer>());

如果这不是编译错误,那么最后一行代码就是可行的。

你可以通过以下方式避免错误:

 List<? extends GenericClass<?>> generic = stringy;

但是你也不能使用add,因为你不知道? extends GenericClass<?>是什么(再次涉及协变)。在这种情况下,你只能枚举列表并期望GenericClass<?>


4

从技术上讲,这是因为 List<GenericClass<String>> 不是 List<GenericClass<?>> 的子类型。为了使其正常工作,您可以进行如下操作:

List<? extends GenericClass<?>> generic = stringy

这应该按预期工作(虽然相当丑陋...)。

例如,有关更多详细信息,请参见此SO问题


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接