来自http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ103:
具有下限的通配符看起来像" ?超类型"和看台 对于类型超类型的所有类型的族,键入Type 包括在内。类型称为下限。
为什么
ArrayList<? super Number> psupn1 = new ArrayList<Number>();
psupn1.add(new Double(2));
编译?
Double不是Number的超类型,而是Number的子类......
编辑1:
ArrayList<? super Number> pextn1 = new ArrayList<Number>();
psupn1.add(new Integer(2));
psupn1.add(new Double(2));
psupn1.add(new Float(2));
for(Number n : psupn1){ // [Invalid] Number should be change to
// Object even if I can only add subtype of Number??
}
答案 0 :(得分:6)
您可以添加 Double
,因为无论类型参数E
是什么,它都可以保证为Number
或超类型...这意味着您绝对可以从Double
转换为E
。你将无法做到:
Number x = psupn1.get(0);
虽然。
考虑一下,并尝试创建逻辑上会破坏它的列表。例如,您不能使用:
// Invalid
ArrayList<? super Number> psupn1 = new ArrayList<Integer>();
psupn1.add(new Double(2));
因为Integer
不是 Number
或超类型 - 它是一个子类。你可以写:
// Valid
ArrayList<? extends Number> psupn1 = new ArrayList<Integer>();
...因为那是另一回事。那时你可以写:
Number x = psupn1.get(0);
因为列表中的任何元素都保证可以转换为到 Number
。这些都是需要转换的方式 - 泛型类型参数或来自。
答案 1 :(得分:5)
Maurice Naftalin和Philip Wadler在Java Generics and Collections中解释得最好:
获取和放置原则:使用 当你得到时,扩展通配符 结构中的值,使用超级 只将值放入时的通配符 一个结构,不要使用通配符 当你们都得到并放好。
答案 2 :(得分:0)
对于任何类型X
,您只能从X
检索List<? extends X>
并仅将X
插入List<? super X>
。但您可以X
插入和检索List<X>
。
在这里,您可以将Number
插入List<? super Number>
的此实例中,当然,您的所有示例new Integer(2)
,new Double(2)
等都是{{1}的实例因此可以将它们放入列表中。
但是如果你在这个列表上调用Number
,你不能认为它只包含数字。要了解为什么请注意这是合法的java代码:
.get()
另请注意, List<Serializable> serializables = new ArrayList<Serializable>();
serializables.add("You know String implements Serializable!");
List<? super Number> list = serializables;
Object o = list.get(0); // Object is your best guess about the result's type
和.get()
中没有任何神奇之处。实际上发生这一切是因为如果你检查.add()
的定义,你可以看到java.util.List<E>
返回.get()
,而E
取add()
作为参数。< / p>
答案 3 :(得分:0)
List<? super Number>
说的是:我们保证您可以将Number
或Number
的任何子类放入此List
。它不能保证你从中得到什么。考虑:
void <T> addToList(List<? super T> list, T... things) {
for (T t: things) {
list.add(t);
}
}
void <T> printList<List<? super T> list) {
for (T t: list) { // doesn't compile
System.out.println(t);
}
for (Object o: list) { // just fine
System.out.println(o);
}
}
public static void main(String[] args) {
List<Object> objects = new ArrayList<Object>();
// 1, 2.0f, 3.0 autoboxed to Integer, Float, Double
addToList(objects, "a string", new Object(), 1, 2.0f, 3.0); // just fine
printList(objects);
List<Number> numbers = new ArrayList<Number>();
addToList(numbers, "a string", new Object(), 1, 2.0f, 3.0); // doesn't compile
addToList(numbers, 1, 2.0f, 3.0); // just fine
printList(numbers);
List<Integer> ints = new ArrayList<Integer>();
addToList(ints, 1, 2.0f, 3.0); // doesn't compile
addToList(ints, 1, 2, 3); // just fine
printList(ints);
}