Java 泛型:列表<;?扩展动物>;与列表相同<;动物>;?

Java 泛型:列表<;?扩展动物>;与列表相同<;动物>;?,java,generics,covariance,extends,contravariance,Java,Generics,Covariance,Extends,Contravariance,我只是想理解Java泛型中的extends关键字 ListList是List的一个子类型,而不是列表表示分配给此变量的值必须是“类型”列表。然而,这并不意味着必须只有Animal对象,也可以有子类 List<Number> l = new ArrayList<Number>(); l.add(4); // autoboxing to Integer l.add(6.7); // autoboxing to Double 这不是您期望的列表,不是列表。但是如果你用List

我只是想理解Java泛型中的
extends
关键字

List
List
List的一个子类型,而不是<代码>列表
表示分配给此变量的值必须是“类型”
列表
。然而,这并不意味着必须只有
Animal
对象,也可以有子类

List<Number> l = new ArrayList<Number>();
l.add(4); // autoboxing to Integer
l.add(6.7); // autoboxing to Double
这不是您期望的
列表
,不是
列表
。但是如果你用
List
List,你就知道你拥有的绝对是一个动物列表。它们不一定都是“动物的”——它们也可以是派生类型。例如,如果你有一个动物列表,一对夫妇可能是山羊,其中一些是猫,等等,这是有道理的,对吗

例如,这是完全有效的:

List<Animal> aL= new List<Animal>();
aL.add(new Goat());
aL.add(new Cat());
Animal a = aL.peek();
a.walk(); // assuming walk is a method within Animal


使用
listhmm。。明白了。很好的解释是+1“这实际上不是我可以持有的对象类型的声明。这是一个关于我可以引用哪些类型的列表的声明。”并且出于同样的原因,你不能做
L.add(new Goat())
因为在第一个示例中,我可能引用的是一个不能添加Goat的狗的列表:),如果您将列表传递给List@DonLi:的确如此。这就是为什么我使用“如果您被允许…”的原因,即在假设的场景中,编译器认为
List
List
的子类型。为什么不使用
void foo(List参数)
void mySub(List<? extends Animal> myList) {
    myList.add(new Cat());     // compile error here
    Animal a = myList.get(0);  // works fine 
}
void mySub(List<? super Animal> myList) {
    myList.add(new Cat());     // works fine
    Animal a = myList.get(0);  // compile error here, since the list entry could be a Plant
}
List<Number> l = new ArrayList<Number>();
l.add(4); // autoboxing to Integer
l.add(6.7); // autoboxing to Double
public void doSomethingWith(List<Number> l) {
    ...
}

List<Double> d = new ArrayList<Double>();
doSomethingWith(d); // not working
public void doSomethingWith(List<? extends Number> l) {
    ...
}

List<Double> d = new ArrayList<Double>();
doSomethingWith(d); // works
List<Animal> aL= new List<Animal>();
aL.add(new Goat());
aL.add(new Cat());
Animal a = aL.peek();
a.walk(); // assuming walk is a method within Animal
aL.peek().meow(); // we can't do this, as it's not guaranteed that aL.peek() will be a Cat
List<? extends Animal> L;
L = aL; // remember aL is a List of Animals
L.add(new Animal()); // throws a compiletime error
List<Goat> gL = new List<Goat>(); // fine
gL.add(new Goat()); // fine
gL.add(new Animal()); // compiletime error