【问题标题】:Java generics, nested collection of wildcardJava泛型,通配符的嵌套集合
【发布时间】:2011-09-11 17:45:50
【问题描述】:

这编译 (1.6)

List<? extends Object> l = new ArrayList<Date>();

但这不是

List<List<? extends Object>> ll = new ArrayList<List<Date>>();

有错误

Type mismatch: cannot convert from ArrayList<List<Date>> to List<List<? extends Object>>

有人能解释一下为什么吗? 谢谢

编辑:为结果而编辑

【问题讨论】:

    标签: java generics wildcard


    【解决方案1】:

    嗯,解释是正确的,但我认为添加实际的工作解决方案也是一件好事;)

    List<? extends List<? extends Object>>
    

    可以正常工作,但显然这种集合的使用受到泛型集合的通常限制的很大限制(但对于更简单的 List 也是如此)

    【讨论】:

      【解决方案2】:

      因为它会破坏类型安全:

      List<List<Object>> lo = new ArrayList<List<Object>>();
      List<List<? extends Object>> ll = lo;
      List<String> ls = new ArrayList<String>();
      ll.add(ls);
      lo.get(0).add(new Object());
      String s = ls.get(0); // assigns a plain Object instance to a String reference
      

      【讨论】:

      • 人们可能想阅读 C# 的 4.0 中添加的泛型接口和委托的协变/逆变声明。这是“解决”这个问题的一种方法(它首先改变了问题)
      • @Voo 看到一篇非常古老的论文“On Variance-Based Subtyping for Parametric Types”。分析了这两种方法的优缺点。 Java 走一条路,C# 走另一条路,但没有什么新东西。正如论文所述,C# 的方法在简单的情况下看起来很简单,但复杂性很容易变得难以管理。 (我不欣赏 C# 人将其呈现为他们发明的、没有缺陷的神奇东西)
      • @irreputable 如果我有时间来讨论一些关于协/逆变的肯定非常重要的话题,我会看这篇论文;)而且泛型一开始很复杂,但能够表达协/逆变可能是有时有用。但是对于胆小的人来说肯定没有什么。但是 Java 一开始就别无选择——我不知道如何实现向后兼容。但是我想每个人都同意 Java 的实现很糟糕,所以在上面添加任何东西真的不是好主意
      • lo.get(0).add(new Object());会引发错误,因为您尝试将对象添加到字符串列表中。
      • @Voo Scala 也是这样做的。
      【解决方案3】:

      假设DB 的子类型,G&lt;T&gt; 是泛型类型

      B x = new D(); // OK
      
      G<B> y = new G<D>(); // FAIL
      

      现在,G&lt;Date&gt;G&lt;?&gt; 的子类型,因此

      G<?> x = new G<Date>();  // OK
      
      G<G<?>> y = new G<G<Date>>(); // FAIL
      

      【讨论】:

        【解决方案4】:

        当分配给具有非通配符泛型类型T的变量(List&lt;T&gt;)时,被分配的对象必须恰好具有T作为其泛型类型(包括T的所有泛型类型参数,通配符和非通配符)。在您的情况下,TList&lt;? extends Object&gt;,它与 List&lt;Date&gt; 的类型不同。

        您可以使用通配符类型,因为List&lt;Date&gt; 可分配给List&lt;? extends Object&gt;

        List<? extends List<? extends Object>> a = new ArrayList<List<Date>>();
        

        【讨论】:

          【解决方案5】:
          <? extends Object>  
          

          表示通配符只能替换为Object 类的子类的那些对象。

          List<List<? extends Object>> ll = new ArrayList<List<Object>>();  
          

          给您类型不匹配的错误,因为您试图将 java 类 Object 的对象列表的 ArrayList 分配给包含作为 java 子类的任何类型对象的 ListListObject

          更多参考,请查看Wildcard documentation

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-04-28
            • 1970-01-01
            • 1970-01-01
            • 2023-03-04
            相关资源
            最近更新 更多