小编典典

Java和Java之间的区别

all

List<? super T>和 和有什么不一样List<? extends T>

我曾经使用过List<? extends T>,但它不允许我向其中添加元素list.add(e),而List<? super T>.


阅读 130

收藏
2022-02-28

共1个答案

小编典典

extends

通配符声明List<? extends Number> 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
  1. 阅读 - 鉴于上述可能的分配,你保证读取什么类型的对象List foo3

    • 您可以阅读 a Number 因为任何可以分配为foo3包含 aNumber或 的子类的列表Number
    • 您无法阅读 anInteger因为foo3可能指向 a List<Double>
    • 您无法阅读 aDouble因为foo3可能指向 a List<Integer>
    • 写作* - 鉴于上述可能的分配,您可以添加什么类型的对象对于上述 所有 可能的分配List foo3是合法的: *ArrayList

    • 您不能添加 ,Integer因为foo3可能指向List<Double>

    • 您不能添加 aDouble因为foo3可能指向 a List<Integer>
    • 您不能添加 aNumber因为foo3可能指向 a List<Integer>

你不能添加任何对象,List<? extends T>因为你不能保证List它真正指向的是什么类型,所以你不能保证那个对象是允许的List。唯一的“保证”是您只能从中读取,并且您将T获得
T.

super

现在考虑List <? super 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
  1. 阅读 - 鉴于上述可能的分配,当您从以下位置阅读时,您保证会收到什么类型的对象List foo3

    • 你不能保证 aInteger因为foo3可能指向 aList<Number>List<Object>
    • 你不能保证 aNumber因为foo3可能指向 a List<Object>
    • 唯一 的保证是您将获得一个 Object 或子类的实例Object(但您不知道是什么子类)。
    • 写作* - 鉴于上述可能的分配,您可以添加什么类型的对象对于上述 所有 可能的分配List foo3是合法的: *ArrayList

    • 您可以添加 an,Integer因为Integer在上述任何列表中都允许使用 an。

    • 您可以添加子类的Integer实例,因为Integer上述任何列表中都允许子类的实例。
    • 您不能添加 aDouble因为foo3可能指向ArrayList<Integer>.
    • 您不能添加 aNumber因为foo3可能指向ArrayList<Integer>.
    • 您不能添加一个,Object因为foo3可能指向一个ArrayList<Integer>.

PECS

记住 PECS“生产者扩展,消费者超级”

  • “Producer Extends” - 如果你需要 aList来产生T值(你想T从列表中读取 s),你需要用 来声明它? extends T,例如List<? extends Integer>. 但是您不能添加到此列表中。

  • “Consumer Super” - 如果你需要 aList来消费T值(你想将Ts 写入列表),你需要用 来声明它? super T,例如List<? super Integer>. 但是不能保证您可以从此列表中读取什么类型的对象。

  • 如果您需要读取和写入列表,则需要完全声明它,不使用通配符,例如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)); 
  } 
}
2022-02-28