简体   繁体   English

Java包装的泛型编译错误

[英]Java wrapped generics compilation error

I have a very basic code to reproduce the issue: 我有一个非常基本的代码来重现该问题:

public class Main {
  public static <T extends Number> void bar(Wrapper<List<T>> wrapper) {
    // do something
  }

  public static void foo(Wrapper<List<? extends Number>> wrapper) {
    // do something
  }

  public static <T extends Number> void bar2(List<T> aList) {
    // do something
  }

  public static void foo2(List<? extends Number> aList) {
    // do something
  }

  public static void main(String[] args) {
    List<Integer> aList = Collections.singletonList(1);
    foo2(aList); // compiles
    bar2(aList); // compiles

    Wrapper<List<Integer>> wrapper = new Wrapper<>(Collections.singletonList(1));
    foo(wrapper); // not compiles
    bar(wrapper); // compiles
  }

  private static class Wrapper<T> {
    private final T t;

    public Wrapper(T t) {
      this.t = t;
    }
  }
}

So the question is why javac gives an error when I try to compile the code: 所以问题是为什么当我尝试编译代码时,javac为什么会给出错误:

Main.java:26: error: method foo in class Main cannot be applied to given types;
    foo(wrapper); // not compiles
    ^
  required: Wrapper<List<? extends Number>>
  found: Wrapper<List<Integer>>
  reason: argument mismatch; Wrapper<List<Integer>> cannot be converted to Wrapper<List<? extends Number>>
1 error

Because Java generics are not covariant. 因为Java泛型不是协变的。

In your case 就你而言

Wrapper<List<Integer>>

instance cannot be used as 实例不能用作

Wrapper<List<? extends Number>>

parameter because 参数,因为

List<Integer>

does not extend 不扩展

List<? extends Number>

Wrapper<List<Integer>> is not a subtype of Wrapper<List<? extends Number>> Wrapper<List<Integer>>不是Wrapper<List<? extends Number>>的子类型Wrapper<List<? extends Number>> Wrapper<List<? extends Number>> . Wrapper<List<? extends Number>>

Use Wrapper<? extends List<? extends Number>> 使用Wrapper<? extends List<? extends Number>> Wrapper<? extends List<? extends Number>> Wrapper<? extends List<? extends Number>> . Wrapper<? extends List<? extends Number>>


To see why you can't pass Wrapper<List<Integer>> to foo , consider the following: I've replaced Wrapper with List , but it's the same thing from a type safety point of view. 要了解为什么不能将Wrapper<List<Integer>>传递给foo ,请考虑以下事项:我已经用List替换了Wrapper ,但是从类型安全的角度来看这是同一回事。

List<List<? extends Number>> list = new ArrayList<>();
List<List<Integer>> intList = new ArrayList<>();

So, you can add something to list : 因此,您可以在list添加一些内容:

List<Double> doubles = new ArrayList<>(Arrays.asList(0.0));
list.add(doubles);

But, if you were able to write this assignment: 但是,如果您能够编写此作业:

list = intList;

Then calling list.add(doubles) would mean there would then be a List<Double> in intList . 然后调用list.add(doubles)意味着intList中将存在一个List<Double> This is not type safe, and thus forbidden. 这不是类型安全的,因此被禁止。

Ideone demo Ideone演示

However, if list has type List<? extend List<? extends Number>> 但是,如果list类型为List<? extend List<? extends Number>> List<? extend List<? extends Number>> List<? extend List<? extends Number>> , then you can't invoke add on it, so you can't get into this situation, so that would be safe. List<? extend List<? extends Number>> ,那么您将无法在其上调用add ,所以您将无法进入这种情况,因此这是安全的。

Because List<Integer> is not a subclass of List<? extends Number> 因为List<Integer>不是List<? extends Number>的子类List<? extends Number> List<? extends Number>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM