【问题标题】:Java nested generic type mismatchJava 嵌套泛型类型不匹配
【发布时间】:2012-11-05 10:15:34
【问题描述】:

在以下示例中:

public static void main(String[] args) {

    List<String> b = new ArrayList<String>();
    first(b);
    second(b);

    List<List<String>> a = new ArrayList<List<String>>();
    third(a);
    fourth(a);  // doesnt work

}

private static <T> void first(List<T> a){
    System.out.println("List of T");
}

private static void second(List<?> a){
    System.out.println("List of anything ");
}

private static <T> void third(List<List<T>> a){
    System.out.println("List of a List of T ");
}

private static void fourth(List<List<?>> a){
    System.out.println("List of a List of anything ");
}

为什么调用 second(b) 有效,但调用 Fourth(a) 却无效

我收到以下错误:

The method fourth(List<List<?>>) in the type `TestTest` is not applicable for the arguments (`List<List<String>>`)

【问题讨论】:

标签: java generics java-6 nested-generics


【解决方案1】:

如果您希望能够使用 List&lt;List&lt;String&gt;&gt; 参数调用 fourth,那么您需要将您的签名更改为:

private static void fourth(List<? extends List<?>> a){
    System.out.println("List of a List of anything ");
}

上述方法会起作用,因为与List&lt;List&lt;?&gt;&gt; 不同,List&lt;? extends List&lt;?&gt;&gt;List&lt;List&lt;String&gt;&gt; 兼容。这样想:

List<List<String>> original = null;
List<? extends List<?>> ok  = original; // This works
List<?> ok2                 = original; // So does this
List<List<?>> notOk         = original; // This doesn't

List<Integer> original      = null;
List<? extends Number> ok   = original; // This works
List<?> ok2                 = original; // So does this
List<Number> notOk          = original; // This doesn't

原因很简单。如果你有

private static void fourth(List<List<?>> a) {
    List<?> ohOh = Arrays.asList(new Object());
    a.add(ohOh);
}

然后如果您可以这样调用该方法:

List<List<String>> a = new ArrayList<List<String>>();
fourth(a);
String fail = a.get(0).get(0); // ClassCastException here!

【讨论】:

  • +1 喜欢这个答案,但需要更多解释为什么 ? extends List&lt;?&gt; 有效?
  • 现场回答卢卡斯!但我相信最后一行应该是String fail = a.get(0).get(0)
  • 为什么是列表> List>? 的超类型
  • @user1799796:我不确定我的条款是否正确。不过,这些类型当然是兼容的。我添加了一个类比,这不是完全相同的东西,而是相似的。当您使用List&lt;? extends Number&gt; 而不是List&lt;? extends List&lt;?&gt;&gt; 时,它可能会感觉更直观。
  • @Andy:差不多。您始终可以传递null 文字,因为null? 的有效值。试试List&lt;?&gt; list = new ArrayList&lt;Object&gt;(); list.add(null);
【解决方案2】:

List&lt;List&lt;String&gt;&gt; 不是 List&lt;List&lt;?&gt;&gt;

无论? 是什么,您都应该能够将任何List&lt;?&gt; 放入List&lt;List&lt;?&gt;&gt;List&lt;List&lt;String&gt;&gt; 只会接受 List&lt;String&gt;

【讨论】:

    【解决方案3】:

    这意味着类型是未知的,任何类型的对象都可以添加到List&lt;List&lt;?&gt;&gt;,即heterogeneous,并且编译器不能保证List&lt;List&lt;?&gt;&gt; 中的所有对象都是相同的类型。因此它不能传递给以有界类型为参数的新ArrayList&lt;List&lt;String&gt;&gt;()

    【讨论】:

      【解决方案4】:

      List&lt;List&lt;String&gt;&gt;List&lt;List&lt;?&gt;&gt; 不同。泛型本质上是不变的。如果你只做List&lt;?&gt; 并通过List&lt;String&gt; 那么它将起作用,因为List of Anything 可以由Lists of String 表示。

      但是List of List of anything不能用List of List of String表示。

      @Lukas Elder 已经指定了可以使用的大小写。这是第二种可行的情况

      private static void fourth(List<?> a){
          System.out.println("List of anything ");
      }
      

      【讨论】:

      • 所以你说Java泛型类型参数没有灵活性?当在泛型中使用类型参数时,实例化对象期望使用泛型类型参数时指定的类型?
      • @kmb385 我必须承认我未能解释评论的含义。使用wild cardsbounded wind cardsbounded types 的泛型类型的灵活性。
      【解决方案5】:
      List<List<?>> == List {                 //That contains any unknown type lists
                              List<Integer>,
                              List<String>,
                              List<Object>
                            }
      

      在哪里

      List<? extends List<?> == List {       //That contains same unknown type lists
                              List<Integer>,
                              List<Integer>,
                              List<Integer>
                            }
      

      所以这里

       List<List<String>> == List {        //That contains same String lists
                              List<String>,
                              List<String>,
                              List<String>
                            }
      

      因此List&lt;? extends List&lt;?&gt;List&lt;List&lt;String&gt;&gt; 的超类型并且可以赋值。

      调用fourth 方法的有效值如下。

          List<List<?>> a1 =  new ArrayList<List<?>>();
          a1.add(new ArrayList<String>());
          a1.add(new ArrayList<Integer>());
          a1.add(new ArrayList<Object>());
      

      【讨论】:

        猜你喜欢
        • 2016-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多