区别? 超级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
-
阅读 – 鉴于上述可能的任务,你保证从
List foo3读取什么types的对象:- 您可以读取一个
Number因为任何可以分配给foo3的列表都包含一个Number或Number的子类。 - 你不能读
Integer因为foo3可能指向一个List<Double>。 - 你不能读一个
Double因为foo3可能指向一个List<Integer>。
- 您可以读取一个
-
写作 – 给定上述可能的赋值,可以将
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 。 唯一的“保证”是你只能读取它,你会得到一个T或T子类。
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
-
阅读 – 鉴于上述可能的任务,当你从
List foo3读取时,你保证接收什么types的对象:- 你不能保证一个
Integer因为foo3可能指向一个List<Number>或者List<Object>。 - 你不能保证一个
Number因为foo3可能指向一个List<Object>。 - 唯一的保证是你将得到一个
Object或Object子类的实例(但你不知道是什么子类)。
- 你不能保证一个
-
写作 – 给定上述可能的赋值,可以将
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值(你想从列表中读取Ts),你需要用? extends T? extends T,例如List<? extends Integer>List<? extends Integer>。 但是你不能添加到这个列表。 -
“消费者超级” – 如果你需要一个
List来消费T值(你想把Ts写入列表),你需要用? 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 :
- C2:
new ArrayList<C2>();,(可以存储C2或子types的对象)或 - D1:
new ArrayList<D1>();,(可以存储D1或子types的对象)或 - 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 ,每种情况都是共同的: C2 , D1 , D2 , E1 , E2 , E3 , E4 。
- 你可以
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 Number , Integer会作为一个<? 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任何超类 (并且不是因为Integer是Number的超类,这不是真的)。
编辑添加了关于消费者扩展和生产者超级评论 – 他们没有意义,因为他们相应地指定什么 ,只是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 class或superclass of A的superclass of A 。
阅读更多: http : //tutorials.jenkov.com/java-generics/wildcards.html
你可以通过上面的所有答案来理解为什么.add()被限制为'<?>' , '<? extends>' '<? extends>' ,部分为'<? super>' '<? super>' 。
但是,如果你想记住这一切,那么这就是所有的结论,并且不想每次都去探索答案:
List<? extends A> List<? extends A>意味着这将接受A任何List和A子类。 但是你不能添加任何东西到这个列表中。 甚至不是typesA对象。
List<? super A> List<? super A>意味着这将接受A和超类的任何列表。 您可以添加AtypesA对象及其子类。