ArrayList <! - ?超级数 - >和双

时间:2011-11-10 16:50:34

标签: java generics

来自http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ103

  

具有下限的通配符看起来像&#34; ?超类型&#34;和看台   对于类型超类型的所有类型的族,键入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??

    }

4 个答案:

答案 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(),而Eadd()作为参数。< / p>

答案 3 :(得分:0)

List<? super Number>说的是:我们保证您可以将NumberNumber的任何子类放入此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);
}