任何人都可以解释为什么我们?
在Collection
泛型中使用。
例如:
List<? extends Number> numberlist;
List<? super Integer> numberlist;
任何人都可以解释为什么我们?
在Collection
泛型中使用。
例如:
List<? extends Number> numberlist;
List<? super Integer> numberlist;
通配符引入了如何使用集合的限制。
例如,使用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超级”。这意味着如果你想让你的列表给你一些东西,它是一个生产者,你应该使用. 如果你想让你的列表接受你的东西,它是一个消费者,所以你使用. 有关更多信息,请参阅此答案。extends
super
但是如果我有一个没有边界的通配符呢?
两者兼而有之!<?>
限制您调用将泛型类型作为参数的方法,并导致所有返回泛型类型的方法返回Object
。这是因为我们不知道类型是什么。例如,所有这些对 a 的赋值List<?>
都是合法的:
List<?> list;
list = new ArrayList<Integer>();
list = new ArrayList<String>();
list = new ArrayList<MyClass>();
等等。
当您学习通配符和extends和super之间的差异时,只需记住PECS。这条规则包含所有内容,非常简单易记。
它是一个通配符。? 表示任何继承自 number 或者是 Integer 类的超类的类都可以工作。希望这可以帮助。:)
?
意思是任何类
? extends MyClass
表示 MyClass 或 MyClass 本身的任何子类。
?
用于在使用泛型时定义通配符。
您在示例中的语句告诉 List 接受任何类型的对象Number
这是我要说的:
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{
}
List<? extends Number>
并且List<Number>
都允许添加例如整数,但是:List<Number>
你可以在那里放入整数和任何其他“是”数字的东西。你可以在List<? extends Number>
那里只放一个具体的运行时类型。无论是整数,那么您就不能添加另一种也是数字的类型。