用于 '?扩展'和'?集合泛型中的 super ' [英] Use of '? extends ' and '? super ' in Collection generics

查看:23
本文介绍了用于 '?扩展'和'?集合泛型中的 super '的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Can anybody explain why we use ? in Collection generics.

例如:

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

推荐答案

通配符限制了集合的使用方式.

The wildcards introduce restrictions in how the collection can be used.

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

For example, with List<? extends Number>, I can't add new elements to the list. This is because all I know is that the list is some kind of subtype of Number, but I don't know what that actual subtype is (so how could I know what to add?). For example, take the following code:

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

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

This won't compile because both of these method calls are legal:

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

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

What you can do is read elements from the list:

// 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,所以我们可以这样对待它以供阅读.

Calls to methods like get will return some kind of Number, we know that for a fact because of the ? extends Number, so we can treat it like that for reading purposes.

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

On the other hand, List<? super Integer> has exactly the opposite result. I can no longer read from the list, but I can write to it. I know that whatever ? is, it will definitely be a super-class of Integer, so concrete types of the list will definitely accept Integer values. For example:

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

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

That code is completely legal. However, if you want to read from the list, the only way to do this is to use Object since anything else requires casting (which requires knowing its concrete type):

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

到底发生了什么

这是实际发生的事情.当您指定 ?扩展数字,您正在使任何元素作为参数的方法都无法使用.事实上,如果您尝试在 Eclipse 中使用 List,在add等方法中将null表示为参数的类型.同时,所有返回元素的方法都保证至少返回某种Number,尽管你不会确切知道Number的哪个子类> 它实际上可能是.

Here's what's actually happening. When you specify ? extends Number, you're making any method that takes elements as a parameter unusable. In fact, if you try to auto-complete code in Eclipse using Ctrl+Space on a List<? extends Number>, it shows null as the parameters' types in the add methods and the like. Meanwhile, all the methods that return elements are guaranteed to return at least some kind of Number, though you won't know exactly which subclass of Number it might actually be.

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

When you specify ? super Integer, you're making any method that takes elements as a parameter guarantee that they'll accept Integer values (and sub-classes of Integer as well). This allows you to call methods like add since you know they'll accept Integer types. Meanwhile, all methods that return elements are only guaranteed to return something, but we don't know what, so all the methods that return elements are only guaranteed to return Object.

PECS 是一个很好的首字母缩写词来记住这一点,它的意思是Producer Extends, Consumer S 上".这意味着如果你想让你的列表给你一些东西,它是一个生产者,你应该使用 extends.如果你想让你的列表接受你的东西,它是一个消费者,所以你使用 super.请参阅此答案了解更多信息.

PECS is an excellent acronym to remember this, it means "Producer Extends, Consumer Supers". This means that if you want your list to give you something, it's a producer, and you should use extends. If you want your list to accept things from you, it's a consumer, so you use super. See this answer for more.

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

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

It does both! <?> restricts you from calling methods that take the generic type as an argument and causes all the methods that return the generic type to return Object. This is because we have no idea what the type is whatsoever. For example, all of these assignments into a List<?> are legal:

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

等等.

这篇关于用于 '?扩展'和'?集合泛型中的 super '的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆