有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java通用列表<列表<?扩展号码>>

为什么在java中我们无法做到:

List<List<? extends Number>> aList = new ArrayList<List<Number>>();

尽管这没问题:

List<? extends Number> aList = new ArrayList<Number>();

编译器错误消息为:

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


共 (5) 个答案

  1. # 1 楼答案

    List<List<? extends Number>> aList = new ArrayList<List<? extends Number>>();
    aList.add(new ArrayList<Integer>());
    
  2. # 2 楼答案

    在Java中,如果CarVehicle的派生类,那么我们可以将所有Cars视为Vehicles;aCar是aVehicle然而,{}的{}也不是{}的{}。我们说List<Car>List<Vehicle>不协变

    Java要求您显式地告诉它何时要使用协方差和逆变与通配符,由?标记表示。看看你的问题发生在哪里:

    List<List<? extends Number>> l = new ArrayList<List<Number>>();
    //        ----------------                          ------
    // 
    // "? extends Number" matched by "Number". Success!
    

    内部List<? extends Number>工作是因为Number确实扩展了Number,所以它匹配“? extends Number”。到目前为止,一切顺利。下一步是什么

    List<List<? extends Number>> l = new ArrayList<List<Number>>();
    //   ----------------------                    ------------
    // 
    // "List<? extends Number>" not matched by "List<Number>". These are
    //   different types and covariance is not specified with a wildcard.
    //   Failure.
    

    但是,组合的内部类型参数List<? extends Number>List<Number>不匹配;类型必须完全相同。另一个通配符将告诉Java,这种组合类型也应该是协变的:

    List<? extends List<? extends Number>> l = new ArrayList<List<Number>>();
    
  3. # 3 楼答案

    您的语句未编译,因为List<? extends Number>List<Number>的类型不同。前者是后者的超类型

    你试过这个吗?在这里,我表示列表在其类型参数中是协变的,因此它将接受List<? extends Number>的任何子类型(包括List<Number>

    List<? extends List<? extends Number>> aList = new ArrayList<List<Number>>();
    

    甚至这个。此处,右侧ArrayList的类型参数与左侧的类型参数相同,因此差异不是问题

    List<List<? extends Number>> aList = new ArrayList<List<? extends Number>>();
    

    你应该可以说

    List<List<Number>> aList = new ArrayList<List<Number>>();
    

    我倾向于尽可能避免使用?类型的通配符。我发现在类型注释中产生的费用不值得这样做

  4. # 4 楼答案

    你一定要用这个?如果合适,请键入通配符,一般不要避免使用通配符。例如:

    public void doThingWithList(List<List<? extends Number>> list);
    

    允许您传递List<Integer>List<Long>

    public void doThingWithList(List<List<Number>> list);
    

    只允许传递声明为List<Number>的参数。一个小的区别,是的,但是使用通配符是强大且安全的。与看起来的相反,aList<Integer>不是子类,或者不可从List<Number>赋值。List<Integer>也不是List<? extends Number的子类,这就是上面的代码无法编译的原因