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>有。
当前回答
的例子, 假设继承顺序为O > S > T > U > V
使用extends关键字,
正确的:
List<? extends T> Object = new List<T>();
List<? extends T> Object = new List<U>();
List<? extends T> Object = new List<V>();
不正确的:
List<? extends T> Object = new List<S>();
List<? extends T> Object = new List<O>();
超级关键字:
正确的:
List<? super T> Object = new List<T>();
List<? super T> Object = new List<S>();
List<? super T> Object = new List<O>();
不正确的:
List<? super T> Object = new List<U>();
List<? super T> Object = new List<V>();
添加对象: List对象= new List();
Object.add(new T()); //error
但是为什么会出错呢? 让我们看看初始化列表对象的可能性
List<? extends T> Object = new List<T>();
List<? extends T> Object = new List<U>();
List<? extends T> Object = new List<V>();
如果我们使用Object。添加(新T ());那么只有当
List<? extends T> Object = new List<T>();
但还有另外两种可能
List对象= new List(); List对象= new List(); 如果我们尝试将(new T())添加到上述两个可能性中,它将会给出一个错误,因为T是U和V的高级类。我们尝试添加一个T对象[它是(new T())]到类型为U和V的列表。高级类对象(基类)不能传递给低级对象(子类)。
由于额外的两种可能性,即使你使用了正确的可能性,Java也会给你错误,因为Java不知道你所指的对象是什么,所以你不能向List中添加对象Object = new List();因为有不成立的可能性。
添加对象: List对象= new List();
Object.add(new T()); // compiles fine without error
Object.add(new U()); // compiles fine without error
Object.add(new V()); // compiles fine without error
Object.add(new S()); // error
Object.add(new O()); // error
但是为什么上面两个会出现错误呢? 我们可以使用Object。添加(新T ());只有在以下的可能性中,
List<? super T> Object = new List<T>();
List<? super T> Object = new List<S>();
List<? super T> Object = new List<O>();
如果我们尝试使用Object。add(new T()) in List对象= new List(); 而且 List对象= new List(); 那么它就会给出错误 这是因为 我们不能将T对象[which is new T()]添加到List object = new List();因为它是U类型的对象。我们不能给U对象添加一个T对象[它是新的T()],因为T是一个基类,U是一个子类。我们不能将基类添加到子类,这就是发生错误的原因。另一种情况也是一样的。
其他回答
我想把区别形象化。假设我们有:
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。
向列表中添加一个项目:
列表< ?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
使用只能从集合中获得的扩展。你不能投入进去。此外,虽然超级允许获取和放置,在获取期间的返回类型是?超级T。
根据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类型的对象。
Super是下界,extends是上界。
根据http://download.oracle.com/javase/tutorial/extra/generics/morefun.html:
解决方法是使用一种形式的 有界通配符我们还没见过 具有下界的通配符。的 语法呢?超级T表示未知 类型是T(或T 本身;记住超类型 关系是自反的)。它是双重的 有界通配符 使用,我们在哪里使用?将T延伸到 表示未知类型 T的子型。