【问题标题】:ArrayList <? super Number> and Double [duplicate]数组列表 <? super Number> 和 Double [重复]
【发布时间】:2011-12-26 08:39:08
【问题描述】:

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

具有下限的通配符看起来像“? super Type”并且代表 对于属于 Type 超类型的所有类型的族,类型 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??

    }

【问题讨论】:

标签: java generics


【解决方案1】:

您可以在其中添加 Double,因为无论类型参数 E 是什么,它都保证是 Number 或超类型...这意味着您绝对可以转换从DoubleE。你将无法做到:

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”吗,我还是不明白
【解决方案2】:

Maurice Naftalin 和 Philip Wadler 在Java Generics and Collections 中解释得最好:

Get 和 Put 原则:使用 当你只得到时扩展通配符 结构中的值,使用 super 仅将值放入时的通配符 结构,不要使用通配符 当你得到和放置时。

【讨论】:

  • +1 这个规则很容易理解!
  • “PECS”(生产者扩展,消费者超级)
【解决方案3】:

对于任何类型的X,您只能从List&lt;? extends X&gt; 中检索X,并且只能将X 插入List&lt;? super X&gt;。但是您可以在List&lt;X&gt; 之间插入和检索X

在这里你可以将任何Number插入List&lt;? super Number&gt;的实例中,当然你所有的例子new Integer(2)new Double(2)等都是Number的实例,所以它们可以放入列表。

但是,如果您在此列表中调用 .get(),您不能假定它仅包含数字。要查看为什么要注意这是合法的 java 代码:

    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&lt;E&gt; 的定义,您会看到 .get() 返回一个 Eadd() 将一个 E 作为参数。

【讨论】:

  • 哇,是不是说Serializable是Number的子类?
  • 不,实际上是因为 Serializable 是 Number 的 超类
【解决方案4】:

List&lt;? super Number&gt; 的意思是:我们保证您可以将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);
}

【讨论】:

    猜你喜欢
    • 2014-03-20
    • 2013-07-23
    • 1970-01-01
    • 2021-08-02
    • 1970-01-01
    • 2014-07-03
    • 1970-01-01
    • 2014-02-09
    • 2019-05-03
    相关资源
    最近更新 更多