用于 '?延伸'和'?超级'收集泛型

Shr*_*ari 5 java generics collections

任何人都可以解释我们?Collection泛型中使用的原因.

例如:

 List<? extends Number> numberlist;
 List<? super Integer> numberlist;
Run Code Online (Sandbox Code Playgroud)

Bri*_*ian 26

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

例如,List<? extends Number>我不能在列表中添加新元素.这是因为我所知道的是列表是某种子类型Number,但我不知道实际的子类型是什么(所以我怎么知道要添加什么?).例如,请使用以下代码:

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

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

doSomethingWith(new ArrayList<Integer>());
doSomethingWith(new ArrayList<Double>());
Run Code Online (Sandbox Code Playgroud)

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

// 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);
}
Run Code Online (Sandbox Code Playgroud)

对类似方法的调用get将返回某种类型Number,我们知道因为这个事实? extends Number,因此我们可以将其视为用于阅读目的.

另一方面,List<? super Integer>恰恰相反.我不能再从列表中读取,但我可以写信给它.我知道无论如何?,它肯定会是一个超类Integer,所以列表的具体类型肯定会接受Integer值.例如:

public void doSomethingWith(List<? super Integer> integers) {
    integers.add(Integer.valueOf(0));
}
Run Code Online (Sandbox Code Playgroud)

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

for (Object obj : integers)
// OR
Object obj = integers.get(0);
// OR
Object obj = integers.remove(0);
Run Code Online (Sandbox Code Playgroud)

什么是真正发生的

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

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

佩奇是一个很好的缩写,记住这一点,它的意思是" P roducer ê xtends,Ç onsumer 小号 upers".这意味着如果您希望列表为您提供某些内容,那么它就是生产者,您应该使用它extends.如果您希望列表接受来自您的内容,那么它就是消费者,因此您可以使用super.请参阅此答案了解更多信息

但是,如果我有一个没有边界的通配符怎么办?

它做到了!<?>限制您打电话的是采取泛型类型作为参数的方法,并导致所有返回的泛型类型返回方法Object.这是因为我们不知道这种类型是什么.例如,所有这些分配到a中List<?>都是合法的:

List<?> list;
list = new ArrayList<Integer>();
list = new ArrayList<String>();
list = new ArrayList<MyClass>();
Run Code Online (Sandbox Code Playgroud)

等等.

  • 很好的答案!谢谢! (2认同)