为什么编译器不会产生错误,因为违反了类型的不变性

时间:2017-09-06 10:53:20

标签: java

一个例子来自Bruce Eckel的书 评论中的问题

class GenericWriting{
static <T> void writeExact(List<T> list, T item) {
    list.add(item);
}
static List<Apple> apples = new ArrayList<Apple>();
static List<Fruit> fruits = new ArrayList<Fruit>();
static void f1() {
    writeExact(apples, new Apple());
    writeExact(fruits, new Apple()); /* why the compiler does not produce an error because the invariance of types is violated */
}
static <T> void writeWithWildcard(List<? super T> list, T item) {
    list.add(item);
}
static void f2() {
    writeWithWildcard(apples, new Apple());
    writeWithWildcard(fruits, new Apple());
}

public static void main(String[] args) {
    f1();
    f2();
}
}

1 个答案:

答案 0 :(得分:0)

这是由于多态性。

通常,如果你写这样的方法:

private static void method(Fruit f) {}

您可以使用new Apple()

进行调用
method(new Apple());

正确?因为AppleFruit的子类。

当你打电话给你的方法时:

writeExact(fruits, new Apple());

由于您没有明确指定T,编译器会尝试推断它。它看到第一个参数fruitsList<Fruit>。它认为T必须是Fruit。现在你的方法是这样的:

static void writeExact(List<Fruit> list, Fruit item)

请参阅?将apple传递给第二个参数是完全正常的,因为AppleFruit的子类。

另一方面,如果您指定通用T to be Apple`,则会出现错误:

List<Fruit> list = new ArrayList<>();
// compiler error!
GenericWriting.<Apple>writeExact(list, new Apple());

因为List<Fruit>List<Apple>不兼容。