上界通配符在 Java 中导致编译错误

Upper bounded wildcards causing compilation error in Java

我不明白为什么会出现这些编译错误:

1:

The method add(capture#1-of ? extends Exec.Bird) in the type List is not applicable for the arguments (Exec.Sparrow)

2:

The method add(capture#2-of ? extends Exec.Bird) in the type List is not applicable for the arguments (Exec.Bird)

static class Bird{}
static class Sparrow extends Bird{}

public static void main(String[] args){
    List<? extends Bird> birds = new ArrayList<Bird>();
    birds.add(new Sparrow()); //#1 DOES NOT COMPILE
    birds.add(new Bird());// //#2 DOES NOT COMPILE
}

您可以像这样实例化 birds 列表:

List<Bird> birds = new ArrayList<>();

完整代码:

import java.util.ArrayList;
import java.util.List;

public class Main {
    static class Bird{}
    static class Sparrow extends Bird{}

    public static void main(String[] args) {
        List<Bird> birds = new ArrayList<>();
        birds.add(new Sparrow());
        birds.add(new Bird());
    }
}

对于 List<? extends Bird>,您实际上说的是 任何类型,它是 Bird 的子类型,或者更准确地说,未知,但特定类型是 Bird 的子类型。这与说 扩展 Bird.

的每种类型不同

也就是说?可以是Sparrow,也可以是Blackbird。如果您尝试将 Sparrow 添加到 可能 仅包含 Blackbird 的列表中,它将不起作用。出于同样的原因,您不能将 Bird 添加到列表中,而 可能 Sparrow 的列表。

为了使事情正常进行,您只需将列表的声明更改为:

List<Bird> birds = new ArrayList<>();

或使用下限:

List<? super Bird> birds = new ArrayList<>();

关于这个下限示例:声明实际上说 任何类型 Bird 或其超类之一 .这意味着您可以安全地添加 SparrowBird,因为它们都满足这些条件。

一般来说,写入列表时应使用? super ...,读取列表时应使用? extends ...。如果您既要阅读又要写作,则不应使用边界。


This answer 提供了关于泛型的非常有用的信息。你绝对应该读一读。