代码之家  ›  专栏  ›  技术社区  ›  Adam Batkin

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

  •  8
  • Adam Batkin  · 技术社区  · 15 年前

    很抱歉,如果标题看起来很混乱,但有些示例是有序的。

    假设我有一些具有泛型类型参数的Java类:

    public class GenericClass<T> {
    }
    

    我可以创建一个类型化的变量来存储一个对象,将泛型参数设置为,比如 String . Java还将让我将变量赋给另一个变量,但将泛型参数设置为通配符。 <?> 类型:

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

    但是,使用带有泛型参数的类时,如果将该参数的类型设置为泛型,则无法将该类的对象分配给相同类型/泛型类型,其中后者(内部/嵌套)参数是通配符类型 <?gt; :

    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<?>>
    

    凭直觉,我认为这个任务不应该是个问题。那么为什么这项任务是个问题呢?

    2 回复  |  直到 15 年前
        1
  •  8
  •   Juri    15 年前

    你面临的问题是有价值的 Covariance .

    List<GenericClass<String>> stringy = ...
    List<GenericClass<?>> generic = stringy;
    generic.add(new GenericClass<Integer>());
    

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

    这样做可以避免错误:

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

    但你不能用 add 也因为你不知道 ? extends GenericClass<?> 是(再次协方差)。在这种情况下,您只能通过列表枚举并期望 GenericClass<?> .

        2
  •  4
  •   Community Egal    7 年前

    从技术上讲,这是因为 List<GenericClass<String>> 不是的子类型 List<GenericClass<?>> . 为了让它工作,你可以做一些像

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

    它应该像预期的那样工作(虽然很难看…)。

    例如,请参见, this SO question 有关详细信息