java - 在集合泛型中使用 '? extends ' 和 '? super '

标签 java generics collections

<分区>

谁能解释一下为什么我们在 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);
}

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

另一方面,List<? super Integer> 的结果正好相反。我无法再从列表中读取,但可以写入。我知道无论 ? 是什么,它肯定是 Integer 的父类(super class),因此列表的具体类型肯定会接受 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生产者E扩展,C消费者S上级”。这意味着如果你想让你的列表给你一些东西,它就是一个生产者,你应该使用 extends 。如果你想让你的列表接受你的东西,它是一个消费者,所以你使用 super 。有关更多信息,请参见 this answer

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

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

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

等等。

关于java - 在集合泛型中使用 '? extends ' 和 '? super ',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12604477/

相关文章:

Java 考试错误检查

c# - 使用普通参数和泛型参数重载构造函数

用于声明抽象泛型类型变量的 C# 语法

java - 多对多对称关系的数据结构( friend 问题)

java - java - 如何在不重新排序的情况下从列表中删除重复项?

java - 是否可以用 selenium 模拟键盘行为?

java - 来自 XML Java Jaxb 的 XSD

javascript - 如何使用 AJAX 将变量值发送到 java servlet? (没有 jQuery)

Java:反射、通用类型和未检查的转换

java - Java 二进制 I/O 问题