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是一个子类。我们不能将基类添加到子类,这就是发生错误的原因。另一种情况也是一样的。
其他回答
通用通配符针对两个主要需求:
从泛型集合读取 插入到泛型集合中 有三种使用通配符定义集合(变量)的方法。这些都是:
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
我想把区别形象化。假设我们有:
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。
Super是下界,extends是上界。
根据http://download.oracle.com/javase/tutorial/extra/generics/morefun.html:
解决方法是使用一种形式的 有界通配符我们还没见过 具有下界的通配符。的 语法呢?超级T表示未知 类型是T(或T 本身;记住超类型 关系是自反的)。它是双重的 有界通配符 使用,我们在哪里使用?将T延伸到 表示未知类型 T的子型。
扩展
List<?数字> 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
Reading - Given the above possible assignments, what type of object are you guaranteed to read from List foo3: You can read a Number because any of the lists that could be assigned to foo3 contain a Number or a subclass of Number. You can't read an Integer because foo3 could be pointing at a List<Double>. You can't read a Double because foo3 could be pointing at a List<Integer>. Writing - Given the above possible assignments, what type of object could you add to List foo3 that would be legal for all the above possible ArrayList assignments: You can't add an Integer because foo3 could be pointing at a List<Double>. You can't add a Double because foo3 could be pointing at a List<Integer>. You can't add a Number because foo3 could be pointing at a List<Integer>.
你不能向List<?extends t>因为你不能保证它真正指向的是什么样的List,所以你不能保证对象被允许在那个List中。唯一的“保证”是你只能读取它,你会得到一个T或T的子类。
超级
现在考虑List <?超级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
Reading - Given the above possible assignments, what type of object are you guaranteed to receive when you read from List foo3: You aren't guaranteed an Integer because foo3 could be pointing at a List<Number> or List<Object>. You aren't guaranteed a Number because foo3 could be pointing at a List<Object>. The only guarantee is that you will get an instance of an Object or subclass of Object (but you don't know what subclass). Writing - Given the above possible assignments, what type of object could you add to List foo3 that would be legal for all the above possible ArrayList assignments: You can add an Integer because an Integer is allowed in any of above lists. You can add an instance of a subclass of Integer because an instance of a subclass of Integer is allowed in any of the above lists. You can't add a Double because foo3 could be pointing at an ArrayList<Integer>. You can't add a Number because foo3 could be pointing at an ArrayList<Integer>. You can't add an Object because foo3 could be pointing at an ArrayList<Integer>.
PECS
记住PECS:“生产者延伸,消费者至上”。
"Producer Extends" - If you need a List to produce T values (you want to read Ts from the list), you need to declare it with ? extends T, e.g. List<? extends Integer>. But you cannot add to this list. "Consumer Super" - If you need a List to consume T values (you want to write Ts into the list), you need to declare it with ? super T, e.g. List<? super Integer>. But there are no guarantees what type of object you may read from this list. If you need to both read from and write to a list, you need to declare it exactly with no wildcards, e.g. List<Integer>.
例子
请注意这个来自Java泛型常见问题解答的例子。注意源列表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));
}
}
也看到 如何添加到List<?extends数字>数据结构?
的例子, 假设继承顺序为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是一个子类。我们不能将基类添加到子类,这就是发生错误的原因。另一种情况也是一样的。