一个例子来自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();
}
}
答案 0 :(得分:0)
这是由于多态性。
通常,如果你写这样的方法:
private static void method(Fruit f) {}
您可以使用new Apple()
:
method(new Apple());
正确?因为Apple
是Fruit
的子类。
当你打电话给你的方法时:
writeExact(fruits, new Apple());
由于您没有明确指定T
,编译器会尝试推断它。它看到第一个参数fruits
是List<Fruit>
。它认为T
必须是Fruit
。现在你的方法是这样的:
static void writeExact(List<Fruit> list, Fruit item)
请参阅?将apple传递给第二个参数是完全正常的,因为Apple
是Fruit
的子类。
另一方面,如果您指定通用T to be
Apple`,则会出现错误:
List<Fruit> list = new ArrayList<>();
// compiler error!
GenericWriting.<Apple>writeExact(list, new Apple());
因为List<Fruit>
与List<Apple>
不兼容。