区别? 超级T>和<? 在Java中扩展T>

List<? super T>什么区别List<? super T> List<? super T>List<? extends T> List<? extends T>

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

extends

List<? extends Number> foo3的通配符声明 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读取什么types的对象:

    • 您可以读取一个Number因为任何可以分配给foo3的列表都包含一个NumberNumber的子类。
    • 你不能读Integer因为foo3可能指向一个List<Double>
    • 你不能读一个Double因为foo3可能指向一个List<Integer>
  2. 写作 – 给定上述可能的赋值,可以将List foo3types的对象添加到List foo3 ,这对于所有上述可能的ArrayList赋值是合法的:

    • 你不能添加一个Integer因为foo3可能指向一个List<Double>
    • 你不能添加一个Double因为foo3可能指向一个List<Integer>
    • 你不能添加一个Number因为foo3可能指向一个List<Integer>

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

super

现在考虑一下List <? super T> List <? super T>

List<? super Integer> foo3的通配符声明 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读取时,你保证接收什么types的对象:

    • 你不能保证一个Integer因为foo3可能指向一个List<Number>或者List<Object>
    • 你不能保证一个Number因为foo3可能指向一个List<Object>
    • 唯一的保证是你将得到一个ObjectObject子类的实例(但你不知道是什么子类)。
  2. 写作 – 给定上述可能的赋值,可以将List foo3types的对象添加到List foo3 ,这对于所有上述可能的ArrayList赋值是合法的:

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

佩奇

记住PECS“生产者延伸,消费者超级”

  • “Producer Extends” – 如果你需要一个List来产生T值(你想从列表中读取T s),你需要用? extends T ? extends T ,例如List<? extends Integer> List<? extends Integer> 。 但是你不能添加到这个列表。

  • “消费者超级” – 如果你需要一个List来消费T值(你想把T s写入列表),你需要用? super T ? super T ,例如List<? super Integer> List<? super Integer> 。 但是不能保证你可以从这个列表中读取什么types的对象。

  • 如果你需要读取和写入列表,你需要声明它完全没有通配符,例如List<Integer>

请注意Javagenerics常见问题中的这个例子 。 注意源列表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)); } } 

另请参阅如何添加到列表<? 扩展Number>数据结构?

想象一下这个层次结构

在这里输入图像描述

1.延长

通过写作

  List<? extends C2> list; 

你是说list将能够引用一个types的对象(例如),其genericstypes是C2 (包括C2 )的7 个子types之一的ArrayList

  1. C2: new ArrayList<C2>(); ,(可以存储C2或子types的对象)或
  2. D1: new ArrayList<D1>(); ,(可以存储D1或子types的对象)或
  3. D2: new ArrayList<D2>(); ,(可以存储D2或子types的对象)或…

等等。 七种不同的情况:

  1) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4 2) new ArrayList<D1>(): can store D1 E1 E2 3) new ArrayList<D2>(): can store D2 E3 E4 4) new ArrayList<E1>(): can store E1 5) new ArrayList<E2>(): can store E2 6) new ArrayList<E3>(): can store E3 7) new ArrayList<E4>(): can store E4 

对于每种可能的情况,我们都有一套“可存储”types:这里用graphics表示7(红色)

在这里输入图像描述

正如你所看到的,没有一种安全的types是每个案件都通用的:

  • 你不能list.add(new C2(){}); 因为它可能是list = new ArrayList<D1>();
  • 你不能list.add(new D1(){}); 因为它可能是list = new ArrayList<D2>();

等等。

超级

通过写作

  List<? super C2> list; 

你是说list将能够引用一个types的对象(例如),其genericstypes是C2的七种超types之一(包括C2 ):

  • A1: new ArrayList<A1>(); ,(可以存储A1或者子types的对象)或者
  • A2: new ArrayList<A2>(); ,(可以存储A2或者子types的对象)或者
  • A3: new ArrayList<A3>(); ,(可以存储A3或子types的对象)或…

等等。 七种不同的情况:

  1) new ArrayList<A1>(): can store A1 B1 B2 C1 C2 D1 D2 E1 E2 E3 E4 2) new ArrayList<A2>(): can store A2 B2 C1 C2 D1 D2 E1 E2 E3 E4 3) new ArrayList<A3>(): can store A3 B3 C2 C3 D1 D2 E1 E2 E3 E4 4) new ArrayList<A4>(): can store A4 B3 B4 C2 C3 D1 D2 E1 E2 E3 E4 5) new ArrayList<B2>(): can store B2 C1 C2 D1 D2 E1 E2 E3 E4 6) new ArrayList<B3>(): can store B3 C2 C3 D1 D2 E1 E2 E3 E4 7) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4 

对于每种可能的情况,我们都有一套“可存储”types:这里用graphics表示7(红色)

在这里输入图像描述

正如你所看到的,在这里我们有七种安全types ,每种情况都是共同的: C2D1D2E1E2E3E4

  • 你可以list.add(new C2(){}); 因为无论我们引用的List是什么types, C2都是允许的
  • 你可以list.add(new D1(){}); 因为无论我们引用的List是什么types, D1都是允许的

等等。 您可能已经注意到,这些types对应于从C2types开始的层次结构。

笔记

这里是完整的层次,如果你想做一些testing

 interface A1{} interface A2{} interface A3{} interface A4{} interface B1 extends A1{} interface B2 extends A1,A2{} interface B3 extends A3,A4{} interface B4 extends A4{} interface C1 extends B2{} interface C2 extends B2,B3{} interface C3 extends B3{} interface D1 extends C1,C2{} interface D2 extends C2{} interface E1 extends D1{} interface E2 extends D1{} interface E3 extends D2{} interface E4 extends D2{} 

我喜欢@Bert F的回答,但这是我的大脑看到的。

我手里有一个X. 如果我想写我的X到一个列表,该列表需要是X的列表或列表X的事情,我可以上传到我的X,即任何超类的X …

 List<? super X> 

如果我得到一个列表,并且想从列表中读出一个X,那么最好是X的列表或X列表,当我读出来的时候,它们可以被上传到X,也就是任何延伸 X

 List<? extends X> 

希望这可以帮助。

基于Bert F的回答,我想解释我的理解。

可以说我们有3个类

 public class Fruit{} public class Melon extends Fruit{} public class WaterMelon extends Melon{} 

我们在这里

 List<? extends Fruit> fruitExtendedList = … //Says that I can be a list of any object as long as this object extends Fruit. 

好,现在让我们尝试从fruitExtendedList中获取一些值

 Fruit fruit = fruitExtendedList.get(position) //This is valid as it can only return Fruit or its subclass. 

再试试吧

 Melon melon = fruitExtendedList.get(position) //This is not valid because fruitExtendedList can be a list of Fruit only, it may not be //list of Melon or WaterMelon and in java we cannot assign sub class object to //super class object reference without explicitly casting it. 

同样的情况

 WaterMelon waterMelon = fruitExtendedList.get(position) 

现在让我们尝试在fruitExtendedList中设置一些对象

添加水果对象

 fruitExtendedList.add(new Fruit()) //This in not valid because as we know fruitExtendedList can be a list of any //object as long as this object extends Fruit. So what if it was the list of //WaterMelon or Melon you cannot add Fruit to the list of WaterMelon or Melon. 

添加瓜类物体

 fruitExtendedList.add(new Melon()) //This would be valid if fruitExtendedList was the list of Fruit but it may //not be, as it can also be the list of WaterMelon object. So, we see an invalid //condition already. 

最后让我们尝试添加WaterMelon对象

 fruitExtendedList.add(new WaterMelon()) //Ok, we got it now we can finally write to fruitExtendedList as WaterMelon //can be added to the list of Fruit or Melon as any superclass reference can point //to its subclass object. 

但是等等 ,如果有人决定让一种新型的柠檬让说为SaltyLemon为理由

 public class SaltyLemon extends Lemon{} 

现在fruitExtendedList可以是Fruit,Melon,WaterMelon或者SaltyLemon的列表。

所以,我们的发言

 fruitExtendedList.add(new WaterMelon()) 

也是无效的。

基本上我们可以说,我们不能写任何东西到一个fruitExtendedList。

这总结了List<? extends Fruit> List<? extends Fruit>

现在让我们看看

 List<? super Melon> melonSuperList= … //Says that I can be a list of anything as long as its object has super class of Melon. 

现在让我们尝试从melonSuperList获得一些价值

 Fruit fruit = melonSuperList.get(position) //This is not valid as melonSuperList can be a list of Object as in java all //the object extends from Object class. So, Object can be super class of Melon and //melonSuperList can be a list of Object type 

同样,Melon,WaterMelon或任何其他物体都不能被读取。

但请注意,我们可以读取对象types实例

 Object myObject = melonSuperList.get(position) //This is valid because Object cannot have any super class and above statement //can return only Fruit, Melon, WaterMelon or Object they all can be referenced by //Object type reference. 

现在,我们尝试从melonSuperList中设置一些值。

添加对象types对象

 melonSuperList.add(new Object()) //This is not valid as melonSuperList can be a list of Fruit or Melon. //Note that Melon itself can be considered as super class of Melon. 

添加水果types的对象

 melonSuperList.add(new Fruit()) //This is also not valid as melonSuperList can be list of Melon 

添加Melontypes对象

 melonSuperList.add(new Melon()) //This is valid because melonSuperList can be list of Object, Fruit or Melon and in //this entire list we can add Melon type object. 

添加WaterMelontypes的对象

 melonSuperList.add(new WaterMelon()) //This is also valid because of same reason as adding Melon 

总结起来,我们可以在melonSuperList中添加Melon或其子类,并只读Object对象。

超级是一个下界,扩展是一个上界。

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

解决scheme是使用我们还没有看到的有界通配符的forms:下界的通配符。 语法? super T表示一个未知types,它是T(或T本身;超types关系是自反的)超types。 这是我们使用的有界通配符的对偶,我们在哪里使用? 扩展T表示一个未知types,它是T的一个子types

使用扩展你只能从集合中获得。 你不能把它放进去。 另外,虽然super允许get和put,get中的返回types是 超级T。 详细的解释在我的博客http://preciselyconcise.com/java/generics/c_wildcards.php

这里最令人困惑的是,无论我们指定什么types的限制,分配只有一个方面:

 baseClassInstance = derivedClassInstance; 

你可能会认为Integer extends NumberInteger会作为一个<? extends Number> <? extends Number> ,但是编译器会告诉你<? extends Number> cannot be converted to Integer <? extends Number> cannot be converted to Integer (也就是说,用人们的说法, 任何扩展的数字都可以转换为Integer是错误的 ):

 class Holder<T> { T v; T get() { return v; } void set(T n) { v=n; } } class A { public static void main(String[]args) { Holder<? extends Number> he = new Holder(); Holder<? super Number> hs = new Holder(); Integer i; Number n; Object o; // Producer Super: always gives an error except // when consumer expects just Object i = hs.get(); // <? super Number> cannot be converted to Integer n = hs.get(); // <? super Number> cannot be converted to Number // <? super Number> cannot be converted to ... (but // there is no class between Number and Object) o = hs.get(); // Consumer Super hs.set(i); hs.set(n); hs.set(o); // Object cannot be converted to <? super Number> // Producer Extends i = he.get(); // <? extends Number> cannot be converted to Integer n = he.get(); o = he.get(); // Consumer Extends: always gives an error he.set(i); // Integer cannot be converted to <? extends Number> he.set(n); // Number cannot be converted to <? extends Number> he.set(o); // Object cannot be converted to <? extends Number> } } 

hs.set(i);可以的,因为Integer可以转换为Number任何超类 (并且不是因为IntegerNumber的超类,这不是真的)。

编辑添加了关于消费者扩展和生产者超级评论 – 他们没有意义,因为他们相应地指定什么 ,只是Object 。 build议您记住PECS,因为CEPS是无用的。

列表<? 扩展X>不允许添加任何东西到列表中。

列表<? 超X>允许添加任何是X(X或其子类)。

何时使用扩展和超级

通配符在方法参数中非常有用。 它们为方法接口提供了必要的灵活性。

人们经常感到困惑的时候使用扩展和何时使用超界。 经验法则是取得原则。 如果你从参数化的容器中获得一些东西,请使用extends。

 int totalFuel(List<? extends Vehicle> list) { int total = 0; for(Vehicle v : list) { total += v.getFuel(); } return total;} 

方法totalFuel从列表中获取交通工具,询问他们有多less燃料,并计算总计。 如果将对象放入参数化的容器中,请使用super。

 int totalValue(Valuer<? super Vehicle> valuer) { int total = 0; for(Vehicle v : vehicles) { total += valuer.evaluate(v); } return total;} 

方法totalValue将车辆放入估值器。 知道扩展绑定比超级更普遍是有用的。

通用通配符针对两个主要需求:

从generics集合中读取插入generics集合有三种方法可以使用generics通配符来定义集合(variables)。 这些是:

 List<?> listUknown = new ArrayList<A>(); List<? extends A> listUknown = new ArrayList<A>(); List<? super A> listUknown = new ArrayList<A>(); 

List<?>表示键入未知types的列表。 这可以是List<A>List<B>List<String>

List<? extends A> List<? extends A>表示作为class A实例的对象的列表,或者subclasses of A (例如B和C)。 List<? super A> List<? super A>意味着列表被input到A classsuperclass of Asuperclass of A

阅读更多: http : //tutorials.jenkov.com/java-generics/wildcards.html

你可以通过上面的所有答案来理解为什么.add()被限制为'<?>''<? extends>' '<? extends>' ,部分为'<? super>' '<? super>'

但是,如果你想记住这一切,那么这就是所有的结论,并且不想每次都去探索答案:

List<? extends A> List<? extends A>意味着这将接受A任何ListA子类。 但是你不能添加任何东西到这个列表中。 甚至不是typesA对象。

List<? super A> List<? super A>意味着这将接受A和超类的任何列表。 您可以添加AtypesA对象及其子类。