java - 难以理解 <? Java 中扩展 T> 通配符

标签 java wildcard extends

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

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

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

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

<小时/>

您可能还会看到why a List<Dog> is not a List<Animal> 这解释了其中的一些原因。通配符是我们在泛型类型之间实现协变的方式。一个List<Dog>不是List<Animal>但它是一个List<? extends Animal> 。这带有我们无法添加到 List<? extends Animal> 的限制。 ,因为它可能是 List<Dog> ,一个List<Cat>或者是其他东西。我们已经不知道了。

还有? super , which is the opposite 。我们可以存储FruitList<? super Fruit>但我们不知道我们会从中取出什么样的物体。它最初声明的类型实际上可能是例如一个List<Object> ,其中还有各种其他东西。

关于java - 难以理解 <? Java 中扩展 T> 通配符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57103279/

相关文章:

Java Jung 图形编辑器

java - 在组合框中选择升序时如何对元素列表进行排序

java - 创建一个在一周中的特定日期执行的触发器(Quartz Scheduler API)

mysql - mysql 中的通配符

android - extends AsyncTask<Void, Void, Long> 是如何工作的

php - 扩展 PDO 类

java - 为 spring mvc 项目创建自定义 jSTL 标签

java - 如何强制 spring org.springframework.format.annotation.DateTimeFormat 为自定义 DateFormatter

Bash shell...查找命令...带通配符的名称...别名或函数

php - MySQL:选择列是给定字符串一部分的行