当前位置: 首页 > 面试题库 >

努力理解Java中的通配符

南宫星波
2023-03-14
问题内容

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

以下代码无法编译(假设Apple扩展了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,在方法内部,我们将丢失有关列表的原始声明类型的信息。在这个例子中,我们可以很清楚地看到为什么我们不能把苹果放在例如中List<? extends Fruit>,因为我们知道列表实际上是一个List<Banana>。再次,通配符告诉我们有关列表的声明类型的信息。

List<? extends Fruit>应该读为“最初声明要保留的列表Fruit或的子类型Fruit,但我们不知道该声明类型是什么”。我们所知道的是,我们从列表中拉出的所有内容都是一个Fruit

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

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

另外还有? super,这是相反的。我们可以将其存储Fruit在中,List<? super Fruit>但我们不知道要从中取出哪种对象。它的原始声明类型实际上可能是例如List<Object>,其中包含各种其他内容。



 类似资料:
  • 我正在youtube上观看opengl的EchernoProject教程,在写opengl中的着色器一集中,他用一行定义了位置属性在着色器中的起始位置: 但我的问题是,为什么他需要这样做,因为当他以前像这样使用glVertexAttribPointer时: 所以在这里,他指定了如何读取缓冲区,包括第一个位置属性索引,那么为什么他还需要像上面一样在着色器中指定它呢?

  • 我真正想做的是使用“RandomNumber”字段,并使用Java类“random”(更具体地说是方法“NextInt()”)将其转换为随机数,然后将其转换为字符串。但我并不真正理解如何在任何地方使用“随机数”字段,我甚至需要getter和setter吗?我可以在任何方法中简单地使用“随机数”作为参数吗? 抱歉,如果这是混淆,非常感谢您的时间!

  • 问题内容: 我在htmlunit中单击链接时遇到问题。我浏览了网站上的api(对此我不太了解),并查看了所有可以找到的示例代码,但是单击链接仍然有问题。 这是错误消息的顶部(它相当大,如果您希望我可以全部提交) 第一页加载正常,但是当我单击第二个链接时,出现此错误(链接为javascript)。这是我的代码的一部分 如果我执行打印链接2,则会得到: 起初我以为HtmlAnchor可能是个问题,所以

  • 问题内容: 我不确定以下代码中的最后一条语句为何非法。应该是的子类型,那么为什么不能将其分配给? 问题答案: 关键是指向 某种 类型的列表,但是编译器不知道该类型是什么,因此它不 知道 向其添加类型是否有效。举个例子,这也是一件好事- 您将向最初创建的用于保存字符串列表的对象添加一个。当然,这些信息在Java执行时会丢失-但是编译器会尽力确保您的安全。 见Java泛型常见问题解答了 很多 的更多信

  • 我是java新手,我在网上读了很多关于还是,但我还是不明白。下面是我的例子: 为什么会有错误?我的问题和评论中提到的不同

  • 问题内容: 我最近喜欢Go编程语言,到目前为止,我发现它很棒,但实际上很难理解接口。我已经阅读了很多有关它们的内容,但对我来说它们仍然很抽象。 我使用下面的接口编写了一些快速的代码: 我真的看不到Circer界面的用途。这些方法已经编写好了,我可以通过直接在结构上直接调用它们而不是使用Circer作为包装器来保存两行代码。 有什么我想念的吗?我使用接口不正确吗?任何帮助或示例,不胜感激。 问题答案