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>有。
当前回答
我想把区别形象化。假设我们有:
class A { }
class B extends A { }
class C extends B { }
列表< ?扩展T> -读取和赋值:
|-------------------------|-------------------|---------------------------------|
| wildcard | get | assign |
|-------------------------|-------------------|---------------------------------|
| List<? extends C> | A B C | List<C> |
|-------------------------|-------------------|---------------------------------|
| List<? extends B> | A B | List<B> List<C> |
|-------------------------|-------------------|---------------------------------|
| List<? extends A> | A | List<A> List<B> List<C> |
|-------------------------|-------------------|---------------------------------|
列表< ?超级T> -写和分配:
|-------------------------|-------------------|-------------------------------------------|
| wildcard | add | assign |
|-------------------------|-------------------|-------------------------------------------|
| List<? super C> | C | List<Object> List<A> List<B> List<C> |
|-------------------------|-------------------|-------------------------------------------|
| List<? super B> | B C | List<Object> List<A> List<B> |
|-------------------------|-------------------|-------------------------------------------|
| List<? super A> | A B C | List<Object> List<A> |
|-------------------------|-------------------|-------------------------------------------|
在所有的情况下:
不管通配符是什么,你总是可以从列表中获得Object。 不管通配符是什么,你总是可以在可变列表中添加null。
其他回答
我喜欢来自@Bert F的答案,但这是我大脑看到的方式。
我手里有个X。如果我想把我的X写进一个列表,这个列表需要是一个X的列表,或者是一个我写X时可以向上转换的列表,即X的任何超类…
List<? super X>
如果我得到一个列表,我想从这个列表中读取一个X,那最好是一个X的列表,或者是一个可以在我读取它们时向上转换为X的列表,即任何扩展X的东西
List<? extends X>
Super是下界,extends是上界。
根据http://download.oracle.com/javase/tutorial/extra/generics/morefun.html:
解决方法是使用一种形式的 有界通配符我们还没见过 具有下界的通配符。的 语法呢?超级T表示未知 类型是T(或T 本身;记住超类型 关系是自反的)。它是双重的 有界通配符 使用,我们在哪里使用?将T延伸到 表示未知类型 T的子型。
你可以通过上面所有的答案来理解为什么.add()被限制为'<?>”、“< ?扩展>',部分扩展到'<?超级>”。
但如果你想记住它,而不想每次都去探索答案,这里是所有问题的结论:
列表< ?extends A>表示它将接受A的任何List和A的子类。 但是你不能在这个列表中添加任何东西。甚至不是A类型的对象。
列表< ?super A>表示它将接受A的任何列表和A的超类。 您可以添加类型A的对象及其子类。
使用只能从集合中获得的扩展。你不能投入进去。此外,虽然超级允许获取和放置,在获取期间的返回类型是?超级T。
何时使用extends和super
通配符在方法参数中最有用。它们允许方法接口中必要的灵活性。
人们经常混淆什么时候使用扩展,什么时候使用超边界。经验法则是“得到-放”原则。如果您从参数化容器中获取某些内容,请使用extends。
int totalFuel(List<? extends Vehicle> list) {
int total = 0;
for(Vehicle v : list) {
total += v.getFuel();
}
return total;}
totalFuel方法从列表中获取车辆,询问它们有多少燃料,并计算总数。 如果将对象放入参数化容器中,请使用super。
int totalValue(Valuer<? super Vehicle> valuer) {
int total = 0;
for(Vehicle v : vehicles) {
total += valuer.evaluate(v);
}
return total;}
totalValue方法将车辆放入Valuer中。 知道扩展界比super更常见是很有用的。