List<之间的区别是什么?super T>和List<?延伸T> ?

我曾经使用List<?扩展T>,但它不允许我添加元素到它的List .add(e),而List<?super T>有。


当前回答

向上投票的答案涵盖了很多方面的细节。然而,我会尝试用不同的方式来回答这个问题。

我们需要考虑两件事,

1. 对列表变量赋值

列表< ?扩展X> listvar;

在这里,X的任何列表或X的子类列表都可以赋值给listvar。

列表<? 扩展 数字> 列表变量; listvar = new ArrayList<Number>(); listvar = new ArrayList<Integer>();


列表< ?super X> listvar;

在这里,X的任何列表或X的超类列表都可以赋值给listvar。

列表<? 超级数字>列表变量; listvar = new ArrayList<Number>(); listvar = new ArrayList<Object>();

2. 对列表变量执行读或写操作

`List<? extends X> listvar;`

您可以使用此特性在方法参数中接受一个列表,并对类型X执行任何操作(注意:您只能从列表中读取类型X的对象)。

`List<? super Number> listvar;

您可以使用此特性在方法参数中接受列表,并对Object类型执行任何操作,因为您只能从列表中读取Object类型的对象。是的,这里还有一点,你可以把X类型的对象添加到列表中。

其他回答

向上投票的答案涵盖了很多方面的细节。然而,我会尝试用不同的方式来回答这个问题。

我们需要考虑两件事,

1. 对列表变量赋值

列表< ?扩展X> listvar;

在这里,X的任何列表或X的子类列表都可以赋值给listvar。

列表<? 扩展 数字> 列表变量; listvar = new ArrayList<Number>(); listvar = new ArrayList<Integer>();


列表< ?super X> listvar;

在这里,X的任何列表或X的超类列表都可以赋值给listvar。

列表<? 超级数字>列表变量; listvar = new ArrayList<Number>(); listvar = new ArrayList<Object>();

2. 对列表变量执行读或写操作

`List<? extends X> listvar;`

您可以使用此特性在方法参数中接受一个列表,并对类型X执行任何操作(注意:您只能从列表中读取类型X的对象)。

`List<? super Number> listvar;

您可以使用此特性在方法参数中接受列表,并对Object类型执行任何操作,因为您只能从列表中读取Object类型的对象。是的,这里还有一点,你可以把X类型的对象添加到列表中。

使用只能从集合中获得的扩展。你不能投入进去。此外,虽然超级允许获取和放置,在获取期间的返回类型是?超级T。

向列表中添加一个项目:

列表< ?extends X >不允许向列表中添加任何东西,除了null。 列表< ?super X >允许添加任何-a X (X或其子类型),或null。

从列表中获取一项:

当你从List< ?扩展X >,你可以将它赋值给X类型的变量或X的任何超类型,包括Object。 当你从List< ?super X >,你只能将它分配给Object类型的变量。

一些例子:

    List<? extends Number> list1 = new ArrayList<Integer>();
    list1.add(null);  //OK
    Number n = list1.get(0);  //OK
    Serializable s = list1.get(0);  //OK
    Object o = list1.get(0);  //OK

    list1.add(2.3);  //ERROR
    list1.add(5);  //ERROR
    list1.add(new Object());  //ERROR
    Integer i = list1.get(0);  //ERROR

    List<? super Number> list2 = new ArrayList<Number>();
    list2.add(null);  //OK
    list2.add(2.3);  //OK
    list2.add(5);  //OK
    Object o = list2.get(0);  //OK

    list2.add(new Object());  //ERROR
    Number n = list2.get(0);  //ERROR
    Serializable s = list2.get(0);  //ERROR
    Integer i = list2.get(0);  //ERROR

扩展

List<?数字> foo3意味着这些都是合法的赋值:

List<? extends Number> foo3 = new ArrayList<Number>();  // Number "extends" Number (in this context)
List<? extends Number> foo3 = new ArrayList<Integer>(); // Integer extends Number
List<? extends Number> foo3 = new ArrayList<Double>();  // Double extends Number

Reading - Given the above possible assignments, what type of object are you guaranteed to read from List foo3: You can read a Number because any of the lists that could be assigned to foo3 contain a Number or a subclass of Number. You can't read an Integer because foo3 could be pointing at a List<Double>. You can't read a Double because foo3 could be pointing at a List<Integer>. Writing - Given the above possible assignments, what type of object could you add to List foo3 that would be legal for all the above possible ArrayList assignments: You can't add an Integer because foo3 could be pointing at a List<Double>. You can't add a Double because foo3 could be pointing at a List<Integer>. You can't add a Number because foo3 could be pointing at a List<Integer>.

你不能向List<?extends t>因为你不能保证它真正指向的是什么样的List,所以你不能保证对象被允许在那个List中。唯一的“保证”是你只能读取它,你会得到一个T或T的子类。

超级

现在考虑List <?超级T >。

List<?super Integer> foo3表示这些都是合法的赋值:

List<? super Integer> foo3 = new ArrayList<Integer>();  // Integer is a "superclass" of Integer (in this context)
List<? super Integer> foo3 = new ArrayList<Number>();   // Number is a superclass of Integer
List<? super Integer> foo3 = new ArrayList<Object>();   // Object is a superclass of Integer

Reading - Given the above possible assignments, what type of object are you guaranteed to receive when you read from List foo3: You aren't guaranteed an Integer because foo3 could be pointing at a List<Number> or List<Object>. You aren't guaranteed a Number because foo3 could be pointing at a List<Object>. The only guarantee is that you will get an instance of an Object or subclass of Object (but you don't know what subclass). Writing - Given the above possible assignments, what type of object could you add to List foo3 that would be legal for all the above possible ArrayList assignments: You can add an Integer because an Integer is allowed in any of above lists. You can add an instance of a subclass of Integer because an instance of a subclass of Integer is allowed in any of the above lists. You can't add a Double because foo3 could be pointing at an ArrayList<Integer>. You can't add a Number because foo3 could be pointing at an ArrayList<Integer>. You can't add an Object because foo3 could be pointing at an ArrayList<Integer>.

PECS

记住PECS:“生产者延伸,消费者至上”。

"Producer Extends" - If you need a List to produce T values (you want to read Ts from the list), you need to declare it with ? extends T, e.g. List<? extends Integer>. But you cannot add to this list. "Consumer Super" - If you need a List to consume T values (you want to write Ts into the list), you need to declare it with ? super T, e.g. List<? super Integer>. But there are no guarantees what type of object you may read from this list. If you need to both read from and write to a list, you need to declare it exactly with no wildcards, e.g. List<Integer>.

例子

请注意这个来自Java泛型常见问题解答的例子。注意源列表src(生产列表)如何使用extends,而目标列表dest(消费列表)如何使用super:

public class Collections { 
  public static <T> void copy(List<? super T> dest, List<? extends T> src) {
      for (int i = 0; i < src.size(); i++) 
        dest.set(i, src.get(i)); 
  } 
}

也看到 如何添加到List<?extends数字>数据结构?

Super是下界,extends是上界。

根据http://download.oracle.com/javase/tutorial/extra/generics/morefun.html:

解决方法是使用一种形式的 有界通配符我们还没见过 具有下界的通配符。的 语法呢?超级T表示未知 类型是T(或T 本身;记住超类型 关系是自反的)。它是双重的 有界通配符 使用,我们在哪里使用?将T延伸到 表示未知类型 T的子型。