加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

苦苦挣扎<?在Java中扩展T> wildcard

发布时间:2020-12-15 04:49:03 所属栏目:Java 来源:网络整理
导读:我有一个非常基本的问题. 下面的代码无法编译(假设Apple Extends Fruit): List? extends Fruit numbers = new ArrayList(); numbers.add(new Apple()); //compile time error 当阅读为什么不,我理解的话,但不是概念:). 让我们假设第一个Fruit不是抽象类.我
我有一个非常基本的问题.

下面的代码无法编译(假设Apple Extends Fruit):

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

当阅读为什么不,我理解的话,但不是概念:).

让我们假设第一个Fruit不是抽象类.我理解,因为我们正在处理多个子类型,所有这些都扩展了Fruit.据说因为我们无法确定水果的确切类型,所以我们不能在收集中加入任何东西.有几件我不明白的事情:

1)显然我们无法知道哪种水果让我感到困惑.在迭代集合时,我们不能通过typeof或其他instanceof检查告诉特定类型吗?

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

我觉得这应该是相当明显的,但有些东西不是为了点击我.任何帮助都很感激.谢谢!

解决方法

理解这一点的最好方法是将通配符视为对列表的一些说法,而不是结果.换一种说法:

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

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

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

名单&LT ;?延伸水果>应该被理解为“最初声明为持有Fruit或某些子类型的Fruit的列表,但我们不知道该声明的类型是什么”.我们所知道的是,我们从列表中提取的所有内容都是Fruit.

此外,你是对的,我们可以迭代列表并使用instanceof来找出列表中真正的内容,但这不会告诉我们列表的原始声明类型.在上面的代码片段中,我们会发现列表中的所有内容都变成了Banana,但我可以轻松地将allBananas声明为List< Fruit>.

您可能还会看到why a List<Dog> is not a List<Animal>,其中解释了其中一些.通配符是我们如何在泛型类型之间进行协方差.列表< Dog>不是List< Animal>但它是一个列表<?扩展动物>.这带来了我们无法添加到List&lt ;?的限制扩展Animal>,因为它可能是List< Dog&gt ;,List< Cat>或者是其他东西.我们不知道了.

还有吗?超级,which is the opposite.我们可以在列表中存储水果<?超级水果>但我们不知道我们将从中抽出什么样的物品.其原始声明的类型实际上可能是例如列表< Object>,其中包含各种其他内容.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读