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>有。
当前回答
Super是下界,extends是上界。
根据http://download.oracle.com/javase/tutorial/extra/generics/morefun.html:
解决方法是使用一种形式的 有界通配符我们还没见过 具有下界的通配符。的 语法呢?超级T表示未知 类型是T(或T 本身;记住超类型 关系是自反的)。它是双重的 有界通配符 使用,我们在哪里使用?将T延伸到 表示未知类型 T的子型。
其他回答
Super是下界,extends是上界。
根据http://download.oracle.com/javase/tutorial/extra/generics/morefun.html:
解决方法是使用一种形式的 有界通配符我们还没见过 具有下界的通配符。的 语法呢?超级T表示未知 类型是T(或T 本身;记住超类型 关系是自反的)。它是双重的 有界通配符 使用,我们在哪里使用?将T延伸到 表示未知类型 T的子型。
这里最令人困惑的是,无论我们指定了什么类型限制,赋值只能以一种方式工作:
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从来都没有用。
的例子, 假设继承顺序为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是一个子类。我们不能将基类添加到子类,这就是发生错误的原因。另一种情况也是一样的。
使用只能从集合中获得的扩展。你不能投入进去。此外,虽然超级允许获取和放置,在获取期间的返回类型是?超级T。
通用通配符针对两个主要需求:
从泛型集合读取 插入到泛型集合中 有三种使用通配符定义集合(变量)的方法。这些都是:
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