苦苦挣扎<?在Java中扩展T> wildcard
我有一个非常基本的问题.
下面的代码无法编译(假设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>.再一次,通配符告诉我们一些关于列表的声明类型的信息. 名单< ;?延伸水果>应该被理解为“最初声明为持有Fruit或某些子类型的Fruit的列表,但我们不知道该声明的类型是什么”.我们所知道的是,我们从列表中提取的所有内容都是Fruit. 此外,你是对的,我们可以迭代列表并使用instanceof来找出列表中真正的内容,但这不会告诉我们列表的原始声明类型.在上面的代码片段中,我们会发现列表中的所有内容都变成了Banana,但我可以轻松地将allBananas声明为List< Fruit>. 您可能还会看到why a 还有吗?超级,which is the opposite.我们可以在列表中存储水果<?超级水果>但我们不知道我们将从中抽出什么样的物品.其原始声明的类型实际上可能是例如列表< Object>,其中包含各种其他内容. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |