难以理解&lt ;?扩展T> Java中的通配符 [英] Struggling with understanding <? extends T> wildcard in Java

查看:86
本文介绍了难以理解&lt ;?扩展T> Java中的通配符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常基本的问题.

I have a very basic question.

以下代码无法编译(假设Apple扩展了水果功能):

The code below doesn't compile (assume Apple Extends Fruit):

    List<? extends Fruit> numbers = new ArrayList<>();
    numbers.add(new Apple());  //compile time error

在阅读为什么不了解的内容时,我理解了这些词,但不理解这个概念:).

When reading about why not, I understand the words but not the concept :).

让我们假设第一个Fruit不是抽象类.我知道,由于我们要处理多个子类型,所有这些子类型都扩展了Fruit.据推测,由于我们无法分辨出确切的水果类型,因此我们无法在集合中放入任何东西.有几件事我不明白:

Let's assume first Fruit is NOT an abstract class. I understand that that since we're dealing with multiple subtypes all of which extend Fruit. Supposedly since we can't tell the exact type of fruit, we can't put anything in the collection. There's a couple things I don't understand:

1)显然我们不知道是哪个水果让我感到困惑.我们不能在遍历集合时通过typeof或其他instanceof检查来告知特定类型吗?

1) Apparently we cannot know which fruit it is which confused me. Wouldn't we be able to tell the specific type through a typeof or other instanceof check while iterating through the collection?

2)假设Fruit是一个具体的类,为什么我们不被允许添加Fruit的实例?这似乎很有意义,因为您至少会知道Fruit的API.即使您不知道Fruit的确切子类型,至少也可以在Fruit()上调用标准方法.

2) Assuming Fruit is a concrete class, why wouldn't we be allowed to add instances of Fruit? It seems like that would make sense because you would know at minimum the API for Fruit. Even if you don't know the exact subtype of Fruit, at least you can invoke the standard methods on Fruit().

我觉得这应该很明显,但是对我来说并没有什么可以点击的.任何帮助,我们感激不尽.谢谢!

I feel like this should be rather obvious but something isn't clicking for me. Any help is appreciate. Thanks!

推荐答案

了解这一点的最好方法是将通配符认为是关于列表的某种说法,而不是对水果的看法.换句话说:

The best way to understand this is to think of the wildcard as saying something about the list, not the fruit. In other words:

List<Banana> allBananas = getMyBananas();
enumerateMyFruit(allBananas);

static void enumerateMyFruit(List<? extends Fruit> myFruit) {
    for (Fruit fruit : myFruit)
        System.out.println(fruit);
}

当我们将allBananas传递给enumerateMyFruit时,在方法内部,我们将丢失有关列表的原始声明类型的信息.在此示例中,我们可以非常清楚地看到为什么我们不能够进行例如将苹果放在List<? extends Fruit>中,因为我们知道列表实际上是List<Banana>.再次,通配符告诉我们有关列表的声明类型的一些信息.

When we pass allBananas to enumerateMyFruit, inside the method we lose information about the original declared type of the list. In this example we can very clearly see why we shouldn't be able to e.g. put apples in a List<? extends Fruit>, because we know that the list is actually a List<Banana>. Again, the wildcard is telling us something about the declared type of the list.

List<? extends Fruit>应该理解为最初声明为保存Fruit的列表或Fruit的某些子类型,但我们不知道该声明的类型是什么".我们所知道的是,我们从列表中拉出的所有内容都是Fruit.

List<? extends Fruit> should be read as something like "a list originally declared to hold Fruit or some subtype of Fruit, but we don't know what that declared type is anymore". All that we know is that everything we pull out of the list is a Fruit.

此外,您是对的,我们可以迭代列表并使用instanceof来查找列表中实际包含的内容,但这并不能告诉我们列表的原始声明类型.在上面的代码片段中,我们发现列表中的所有内容都是Banana,但是我可以像List<Fruit>一样容易地声明allBananas.

Also, you are right, we could iterate the list and use instanceof to find out what is really in the list, but this wouldn't tell us the original declared type of the list. In the above code snippet we would find out that everything in the list turned out to be a Banana, but I could have just as easily declared allBananas as a List<Fruit>.

您可能还会看到为什么List<Dog>不是List<Animal> 的原因.通配符是我们如何在泛型类型之间进行协方差. List<Dog>不是List<Animal>,而是List<? extends Animal>.这带有我们不能添加到List<? extends Animal>的限制,因为它可能是List<Dog>List<Cat>或其他内容.我们不知道了.

You might also see why a List<Dog> is not a List<Animal> which explains some of this. The wildcard is how we have covariance among generic types. a List<Dog> is not a List<Animal> but it is a List<? extends Animal>. This comes with the restriction that we can't add to a List<? extends Animal>, because it might be a List<Dog>, a List<Cat> or something else. We don't know anymore.

还有? super与之相反.我们可以将Fruit存储在List<? super Fruit>中,但是我们不知道我们将提取哪种对象.其原始声明的类型实际上可能是List<Object>,其中包含其他各种内容.

There's also the ? super, which is the opposite. We can store Fruit in a List<? super Fruit> but we don't know what kinds of objects we will pull out of it. Its original declared type might actually be e.g. a List<Object>, with all kinds of other stuff in it.

这篇关于难以理解&lt ;?扩展T&gt; Java中的通配符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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