Ana*_*and 751 java generics collections
List<? super T>
和之间有什么区别List<? extends T>
?
我曾经使用List<? extends T>
,但它不允许我添加元素list.add(e)
,而List<? super T>
它.
Ber*_*t F 1402
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
Run Code Online (Sandbox Code Playgroud)
阅读 - 鉴于上述可能的分配,您可以保证从哪种类型的对象中读取List foo3
:
Number
因为可以分配的任何列表foo3
包含a Number
或子类Number
.Integer
因为foo3
可能指向一个List<Double>
.Double
因为foo3
可能指向一个List<Integer>
.写作 - 鉴于上述可能的分配,您可以添加哪种类型的对象List foo3
对于上述所有可能的ArrayList
分配都是合法的:
Integer
因为foo3
可能指向一个List<Double>
.Double
因为foo3
可能指向一个List<Integer>
.Number
因为foo3
可能指向一个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
Run Code Online (Sandbox Code Playgroud)
阅读 - 鉴于上述可能的分配,当您阅读时,您保证会收到什么类型的对象List foo3
:
Integer
因为foo3
可能指向一个List<Number>
或List<Object>
.Number
因为foo3
可能指向一个List<Object>
.Object
或子类的Object
(但你不知道什么是子类).写作 - 鉴于上述可能的分配,您可以添加哪种类型的对象List foo3
对于上述所有可能的ArrayList
分配都是合法的:
Integer
因为Integer
上述任何列表都允许使用.Integer
的实例,因为Integer
在上述任何列表中都允许子类的实例.Double
因为foo3
可能指向一个ArrayList<Integer>
.Number
因为foo3
可能指向一个ArrayList<Integer>
.Object
因为foo3
可能指向一个ArrayList<Integer>
.记住PECS:"制片人扩展,消费者超级".
"生产者扩展" - 如果您需要List
生成T
值(您希望T
从列表中读取s),则需要声明它? extends T
,例如List<? extends Integer>
.但是您无法添加到此列表中.
"消费者超级" - 如果您需要List
消费T
值(您想要将T
s写入列表),您需要声明它? super T
,例如List<? super Integer>
.但是无法保证您可以从此列表中读取哪种类型的对象.
如果您需要同时读取和写入列表,则需要在没有通配符的情况下完全声明它,例如List<Integer>
.
请注意Java Generics FAQ中的此示例.请注意源列表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));
}
}
Run Code Online (Sandbox Code Playgroud)
Lui*_*ese 220
想象一下这个层次结构
通过写作
List<? extends C2> list;
Run Code Online (Sandbox Code Playgroud)
你说这list
将能够引用一个类型的对象(例如),ArrayList
其泛型类型是(包括)的7 个子类型之一:C2
C2
new ArrayList<C2>();
,(可以存储C2或子类型的对象)或new ArrayList<D1>();
,(可以存储D1或子类型的对象)或new ArrayList<D2>();
,(可以存储D2或子类型的对象)或......等等.七种不同的情况:
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
Run Code Online (Sandbox Code Playgroud)
对于每种可能的情况,我们有一组"可存储"类型:此处以图形方式表示7(红色)集
如您所见,并非每种情况都有一种安全类型:
list.add(new C2(){});
因为它可能list = new ArrayList<D1>();
list.add(new D1(){});
因为它可能list = new ArrayList<D2>();
等等.
通过写作
List<? super C2> list;
Run Code Online (Sandbox Code Playgroud)
你说这list
将能够引用一个类型的对象(例如),ArrayList
其泛型类型是(包括)的7个超类型之一:C2
C2
new ArrayList<A1>();
,(可以存储A1或子类型的对象)或new ArrayList<A2>();
,(可以存储A2或子类型的对象)或new ArrayList<A3>();
,(可以存储A3或子类型的对象)或......等等.七种不同的情况:
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
Run Code Online (Sandbox Code Playgroud)
对于每种可能的情况,我们有一组"可存储"类型:此处以图形方式表示7(红色)集
正如你所看到的,在这里我们有七个安全类型是共同的每一种情况下:C2
,D1
,D2
,E1
,E2
,E3
,E4
.
list.add(new C2(){});
因为,无论我们引用哪种List,C2
都是允许的list.add(new D1(){});
因为,无论我们引用哪种List,D1
都是允许的等等.您可能已经注意到这些类型对应于从类型开始的层次结构C2
.
如果您想进行一些测试,这里是完整的层次结构
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{}
Run Code Online (Sandbox Code Playgroud)
Mic*_*ann 86
我喜欢@Bert F的答案,但这是我大脑看到它的方式.
我手里拿着一个X. 如果我想将我的X写入List,那么List需要是一个X列表或一个我可以将X写入其中的事物列表,因为我将它们写入,即任何超类 X ...
List<? super X>
Run Code Online (Sandbox Code Playgroud)
如果我得到一个List并且我想要读取该列表中的X,那么最好是X的列表或者在我读出它时可以向上转换为X的列表,即任何扩展 X的东西
List<? extends X>
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助.
Sus*_*ant 19
根据Bert F的回答,我想解释一下我的理解.
可以说我们有3个班级
public class Fruit{}
public class Melon extends Fruit{}
public class WaterMelon extends Melon{}
Run Code Online (Sandbox Code Playgroud)
我们在这里
List<? extends Fruit> fruitExtendedList = …
//Says that I can be a list of any object as long as this object extends Fruit.
Run Code Online (Sandbox Code Playgroud)
好的,现在让我们尝试从fruitExtendedList获取一些值
Fruit fruit = fruitExtendedList.get(position)
//This is valid as it can only return Fruit or its subclass.
Run Code Online (Sandbox Code Playgroud)
再来试试吧
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.
Run Code Online (Sandbox Code Playgroud)
情况也是如此
WaterMelon waterMelon = fruitExtendedList.get(position)
Run Code Online (Sandbox Code Playgroud)
现在让我们尝试在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.
Run Code Online (Sandbox Code Playgroud)
添加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.
Run Code Online (Sandbox Code Playgroud)
最后让我们尝试添加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.
Run Code Online (Sandbox Code Playgroud)
但是等一下,如果有人决定制作一种新型的柠檬,可以说是为了争论SaltyLemon
public class SaltyLemon extends Lemon{}
Run Code Online (Sandbox Code Playgroud)
现在fruitExtendedList可以是Fruit,Melon,WaterMelon或SaltyLemon的列表.
所以,我们的声明
fruitExtendedList.add(new WaterMelon())
Run Code Online (Sandbox Code Playgroud)
也无效.
基本上我们可以说我们不能向fruitExtendedList写任何东西.
这总结了一下 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.
Run Code Online (Sandbox Code Playgroud)
现在让我们尝试从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
Run Code Online (Sandbox Code Playgroud)
同样,Melon,WaterMelon或任何其他物体都无法读取.
但请注意,我们可以读取对象类型实例
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.
Run Code Online (Sandbox Code Playgroud)
现在,让我们尝试从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.
Run Code Online (Sandbox Code Playgroud)
添加Fruit类型对象
melonSuperList.add(new Fruit())
//This is also not valid as melonSuperList can be list of Melon
Run Code Online (Sandbox Code Playgroud)
添加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.
Run Code Online (Sandbox Code Playgroud)
添加WaterMelon类型对象
melonSuperList.add(new WaterMelon())
//This is also valid because of same reason as adding Melon
Run Code Online (Sandbox Code Playgroud)
总结一下,我们可以在melonSuperList中添加Melon或其子类,并且只读取Object类型对象.
Ist*_*tao 16
super是下限,extends是上限.
根据http://download.oracle.com/javase/tutorial/extra/generics/morefun.html:
解决方案是使用一种我们尚未见过的有界通配符形式:具有下限的通配符.语法?super T表示一个未知类型,它是T的超类型(或T本身;记住超类型关系是自反的).它是我们一直在使用的有界通配符的双重身份,我们在哪里使用?扩展T表示一个未知类型,它是T的子类型.
Ole*_*hov 12
我想想象一下这种差异.假设我们有:
class A { }
class B extends A { }
class C extends B { }
Run Code Online (Sandbox Code Playgroud)
List<? extends 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> |
|-------------------------|-------------------|---------------------------------|
Run Code Online (Sandbox Code Playgroud)
List<? super 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> |
|-------------------------|-------------------|-------------------------------------------|
Run Code Online (Sandbox Code Playgroud)
在所有情况下:
Object
从列表中获取.null
到可变列表中.ely*_*yor 10
向列表中添加一个项目:
列表< ? extends X >不允许添加任何东西,除了null
到列表中。
列表< ? super X >允许添加任何是 X(X 或其子类型)或 null 的内容。
从列表中获取项目:
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
投票的答案涵盖了许多方面的细节。不过,我会尝试以不同的方式回答这个问题。
我们需要考虑两件事,
List<? extends X> listvar;
这里,任何X 列表或 X 子类列表都可以分配给 listvar。
List<? extends Number> listvar;
listvar = new ArrayList<Number>();
listvar = new ArrayList<Integer>();
List<? super X> listvar;
这里,任何X 列表或 X 超类列表都可以分配给 listvar。
List<? super Number> listvar;
listvar = new ArrayList<Number>();
listvar = new ArrayList<Object>();
`List<? extends X> listvar;`
Run Code Online (Sandbox Code Playgroud)
您可以使用此功能接受方法参数中的列表并对类型 X执行任何操作(注意:您只能从列表中读取类型 X 的对象)。
`List<? super Number> listvar;
Run Code Online (Sandbox Code Playgroud)
您可以使用此功能接受方法参数中的列表并对对象类型执行任何操作,因为您只能从列表中读取对象类型的对象。但是,是的,这里的附加事项是,您可以将类型 X 的对象添加到列表中。
你可以通过上面所有的答案,明白为什么.add()
被限制'<?>'
,'<? extends>'
以及部分原因'<? super>'
。
但是如果你想记住它,并且不想每次都去探索答案,这里是所有的结论:
List<? extends A>
这意味着将接受任何List
的A
和子类A
。但是您不能在此列表中添加任何内容。甚至不是类型的对象A
。
List<? super A>
这意味着将接受任何列表A
和超类A
。您可以添加类型的对象A
及其子类。
归档时间: |
|
查看次数: |
206311 次 |
最近记录: |