泛型中的通配符:"?super T"有效,而"?T"则不然?

mak*_*aks 5 java generics java-7

我的问题是关于Java 7中的泛型.假设我们有这样的类层次结构:

interface Animal {}    
class Lion implements Animal {}    
class Butterfly implements Animal {}
Run Code Online (Sandbox Code Playgroud)

就像在Java Generics Tutorial中一样

我们还有一堂课

class Cage<T> {
    private List<T> arr = new ArrayList<>();
    public void add(T t) {
        arr.add(t);
    }
    public T get() {
        return arr.get(0);
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是使用该类的代码:

public static void main(String[] args) {
        Cage<? extends Animal> cage = new Cage<>();
        Animal a = cage.get(); //OK
        cage.add(new Lion()); //Compile-time error
        cage.add(new Butterfly()); //Compile-time error   
    }
Run Code Online (Sandbox Code Playgroud)

问题#1:

我在这里已经阅读过这些问题,但简直就是这样Cage<?>.但我告诉编译器<? extends Animal>这样类型TCage<T>将是任何动物类型的亚型.那么为什么它仍然会产生编译时错误?

问题2:

如果我指定Cage<? super Animal> cage = ...而不是Cage<? extends Animal> cage = ...一切正常,编译器没有说什么坏.为什么在这种情况下它工作正常,而在上面的例子中失败?

Ed *_*aub 6

笼子必须能够容纳两种类型的动物."超级"说 - 它说凯奇必须能够容纳所有类型的动物 - 也许还有其他一些东西,因为它? super Animal可能是动物的超类."延伸"说它可以容纳某些种类的动物 - 例如,可能只是狮子会,如:

Cage<? extends Animal> cage = new Cage<Lion>();
Run Code Online (Sandbox Code Playgroud)

这将是一个有效的陈述,但显然狮子笼不会持蝴蝶,所以

cage.add(new Butterfly());   
Run Code Online (Sandbox Code Playgroud)

不会编译.该声明

cage.add(new Lion());
Run Code Online (Sandbox Code Playgroud)

也不会编译,因为这里的Java正在查看笼子的声明Cage<? extends Animal>- 而不是现在分配给它的对象(Cage<Lion>).

我所知道的泛型的最佳描述是在O'Reilly的Java中的Nutshell中.本章免费在线 - 第1 部分第2部分.