上限有限的通配符导致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)

1
2
3
4
5
6
7
8
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
}


对于List,你实际上说的是任何一种鸟类的亚型。这和说每种扩展Bird的类型不同。

这意味着?可以是Sparrow,但也可以是Blackbird。如果你试图将一个Sparrow添加到一个只包含Blackbird的列表中,那么它将不起作用。出于同样的原因,您不能将Bird添加到可能是Sparrow的列表中。

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

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

或使用下限:

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

关于这个下界示例:声明实际上表示任何类型的Bird或其超类之一。这意味着您可以安全地添加SparrowBird,因为两者都符合这些标准。

一般来说,你在写清单的时候应该使用? super ...,在读清单的时候应该使用? extends ...。如果你既读又写,你不应该使用界限。

这个答案提供了非常有用的关于泛型的信息。你绝对应该读。


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

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

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
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());
    }
}