List<之间的区别是什么?super T>和List<?延伸T> ?
我曾经使用List<?扩展T>,但它不允许我添加元素到它的List .add(e),而List<?super T>有。
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类型的对象添加到列表中。
其他回答
我喜欢来自@Bert F的答案,但这是我大脑看到的方式。
我手里有个X。如果我想把我的X写进一个列表,这个列表需要是一个X的列表,或者是一个我写X时可以向上转换的列表,即X的任何超类…
List<? super X>
如果我得到一个列表,我想从这个列表中读取一个X,那最好是一个X的列表,或者是一个可以在我读取它们时向上转换为X的列表,即任何扩展X的东西
List<? extends X>
这里最令人困惑的是,无论我们指定了什么类型限制,赋值只能以一种方式工作:
baseClassInstance = derivedClassInstance;
您可能认为Integer扩展了Number,并且Integer可以作为<?扩展数字>,但是编译器会告诉你<?extends Number>不能转换为Integer(也就是说,在人类的说法中,任何扩展Number的东西都可以转换为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(我);是可以的,因为Integer可以转换为Number的任何超类(而不是因为Integer是Number的超类,这不是真的)。
EDIT添加了一条关于消费者扩展和生产者超级的注释——它们没有意义,因为它们相应地指定了什么,而只是对象。建议您记住PECS,因为CEPS从来都没有用。
根据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.
最后让我们尝试添加西瓜对象
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<?扩展了水果>
现在让我们看看
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、Melon或其他任何对象都不能读取。
但请注意,我们可以读取对象类型实例
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中设置一些值。
添加对象类型对象
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.
添加水果类型对象
melonSuperList.add(new Fruit())
//This is also not valid as melonSuperList can be list of Melon
添加Melon类型对象
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.
添加西瓜类型对象
melonSuperList.add(new WaterMelon())
//This is also valid because of same reason as adding Melon
综上所述,我们可以在melonSuperList中添加Melon或其子类,并且只读取Object类型的对象。
通用通配符针对两个主要需求:
从泛型集合读取 插入到泛型集合中 有三种使用通配符定义集合(变量)的方法。这些都是:
List<?> listUknown = new ArrayList<A>();
List<? extends A> listUknown = new ArrayList<A>();
List<? super A> listUknown = new ArrayList<A>();
列表< ?>表示输入未知类型的列表。这可以是一个列表< a >,一个列表<B>,一个列表<字符串>等。
列表< ?extends A>表示A类的实例或A的子类(例如B和C)的对象列表。 列表< ?super A>表示列表被输入到A类或A的超类。
阅读更多信息:http://tutorials.jenkov.com/java-generics/wildcards.html
向列表中添加一个项目:
列表< ?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