6

任何人都可以解释为什么我们?Collection泛型中使用。

例如:

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

7 回答 7

29

通配符引入了如何使用集合的限制。

例如,使用List<? extends Number>,我无法将新元素添加到列表中。这是因为我只知道列表是 的某种子类型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);
}

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

另一方面,List<? super Integer>却有着完全相反的结果。我不能再从列表中读取,但我可以写入它。我知道不管?是什么,它肯定是 的超类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 中使用 Ctrl+Space 自动完成代码,它会在方法等中List<? extends Number>显示null为参数的类型。add同时,所有返回元素的方法都保证至少返回某种Number,尽管您不会确切知道Number它实际上可能是哪个子类。

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

PECS 是一个很好的首字母缩略词来记住这一点,它的意思是“ P生产者扩展,消费者S超级”。这意味着如果你想让你的列表给你一些东西,它是一个生产者,你应该使用. 如果你想让你的列表接受你的东西,它是一个消费者,所以你使用. 有关更多信息,请参阅此答案extendssuper

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

两者兼而有之!<?>限制您调用将泛型类型作为参数的方法,导致所有返回泛型类型的方法返回Object。这是因为我们不知道类型是什么。例如,所有这些对 a 的赋值List<?>都是合法的:

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

等等。

于 2012-09-26T15:33:46.590 回答
2

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

于 2012-09-26T15:06:36.503 回答
2

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

于 2012-09-26T14:55:39.197 回答
1

?意思是任何类

? extends MyClass

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

于 2012-09-26T14:53:01.900 回答
1

?用于在使用泛型时定义通配符。

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

于 2012-09-26T14:52:02.557 回答
1

这是我要说的:

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{
}
于 2012-09-26T15:02:33.263 回答
0

List<? extends Number>并且List<Number>都允许添加例如整数,但是:List<Number>你可以在那里放入整数和任何其他“是”数字的东西。你可以在List<? extends Number>那里只放一个具体的运行时类型。无论是整数,那么您就不能添加另一种也是数字的类型。

于 2012-09-26T15:06:49.773 回答