【问题标题】:Use of '? extends ' and '? super ' in Collection generics [duplicate]用于 '?扩展'和'?集合泛型中的超级'
【发布时间】:2012-09-18 05:47:21
【问题描述】:

谁能解释为什么我们在Collection泛型中使用?

例如:

 List<? extends Number> numberlist;
 List<? super Integer> numberlist;

【问题讨论】:

标签: java generics collections


【解决方案1】:

通配符对集合的使用方式进行了限制。

例如,使用List&lt;? extends Number&gt;,我无法将新元素添加到列表中。这是因为我只知道该列表是Number 的某种子类型,但我不知道实际的子类型是什么(所以我怎么知道要添加什么?)。比如下面的代码:

public void doSomethingWith(List<? extends Number> numbers) {
    numbers.add(Integer.valueOf(0)); // Won't compile
}

这不会编译,因为这些方法调用都是合法的:

doSomethingWith(new ArrayList<Integer>());
doSomethingWith(new ArrayList<Double>());

可以做的是读取列表中的元素:

// This will all compile
public void doSomethingWith(List<? extends Number> numbers) {
    for (Number number : numbers) {
        // Do something with number
    }
    // OR
    Number number = numbers.get(0);
    // OR
    Number number = numbers.remove(0);
}

调用get 之类的方法将返回某种Number,我们知道这是因为? extends Number,所以我们可以这样对待它以供阅读。

另一方面,List&lt;? super Integer&gt; 的结果正好相反。我不能再从列表中读取,但我可以写入它。我知道无论? 是什么,它肯定是Integer 的超类,所以列表的具体类型肯定会接受Integer 值。例如:

public void doSomethingWith(List<? super Integer> integers) {
    integers.add(Integer.valueOf(0));
}

该代码是完全合法的。但是,如果你想从列表中读取,唯一的方法是使用Object,因为其他任何东西都需要强制转换(这需要知道它的具体类型):

for (Object obj : integers)
// OR
Object obj = integers.get(0);
// OR
Object obj = integers.remove(0);

到底发生了什么

这是实际发生的事情。当您指定? extends Number 时,您正在使 元素作为参数的任何方法都无法使用。事实上,如果您尝试在 Eclipse 中对 List&lt;? extends Number&gt; 使用 Ctrl+Space 自动完成代码,它会将 null 显示为 add 方法等中的参数类型。同时,返回元素的所有方法都保证至少返回某种Number,尽管你不会确切知道它实际上可能是Number的哪个子类。

当您指定? super Integer 时,您正在使任何 元素作为参数的方法保证它们将接受Integer 值(以及Integer 的子类) )。这允许您调用像 add 这样的方法,因为您知道它们会接受 Integer 类型。同时,所有返回元素的方法都只保证返回something,但我们不知道是什么,所以所有返回元素的方法都只保证返回@987654348 @。

PECS 是一个很好的首字母缩略词来记住这一点,它的意思是“P生产者 Extends,Consumer S上级”。这意味着如果你想让你的列表给你一些东西,它是一个生产者,你应该使用extends。如果你希望你的列表接受你的东西,它是一个消费者,所以你使用super。请参阅this answer 了解更多信息。

但是如果我有一个没有边界的通配符呢?

两者兼得! &lt;?&gt; 限制您调用将泛型类型作为参数的方法并且 导致所有返回泛型类型的方法返回Object。这是因为我们不知道类型是什么。例如,List&lt;?&gt; 中的所有这些分配都是合法的:

List<?> list;
list = new ArrayList<Integer>();
list = new ArrayList<String>();
list = new ArrayList<MyClass>();

等等。

【讨论】:

  • 优秀的答案!谢谢!
【解决方案2】:

List&lt;? extends Number&gt;List&lt;Number&gt; 都允许添加例如整数,但是: 使用List&lt;Number&gt;,您可以在其中放入整数和其他任何“是”数字的东西。使用List&lt;? extends Number&gt;,您只能在其中放入一个具体的运行时类型。无论是 Integer,您都不能添加其他类型也是 Number。

【讨论】:

    【解决方案3】:

    当您学习通配符和 extendssuper 之间的差异时,只需记住 PECS。这条规则包含了所有内容,而且非常简单易记。

    【讨论】:

      【解决方案4】:

      我想说的是:

      List<? extends Number> numberlist; //Any class that is extended from Number class,  for example Integer, BigInt, ... may come
      
      List<? super Integer> numberlist; //Any class that Integer class is extended from. Here for example Number may come
      

      因为:

      Integer extends Number{
      }
      

      【讨论】:

        【解决方案5】:

        它是一个通配符。 ?表示任何继承自 number 或者是 Integer 类的超类的类都可以工作。希望这可以帮助。 :)

        【讨论】:

          【解决方案6】:

          ? 表示任何类,所以

          ? extends MyClass
          

          表示 MyClass 的任何子类或 MyClass 本身。

          【讨论】:

            【解决方案7】:

            ? 用于在使用泛型时定义 wild cards

            您在示例中的语句告诉 List 接受 Number 类型的任何对象

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-10-21
              • 2012-10-19
              • 1970-01-01
              • 1970-01-01
              • 2012-08-30
              • 2010-12-27
              • 1970-01-01
              • 2018-11-20
              相关资源
              最近更新 更多