import java.util.*;
class  Generic
{
public static void main(String[] args) 
{
List<Animal> list=new ArrayList<Animal>();
 fun(list);
  

}
static void fun(List<? super Dog> o){ o.add(new Animal());

}
}
class Dog extends Animal
{
}
class Animal 
{
}为什么编译不能通过 换成? super Animal就行

解决方案 »

  1.   

    看完java tutorial 之后有点明白了这是java tutorial 上的例子
    class AnimalHouse<E> {
        private E animal;
        public void setAnimal(E x) {
            animal = x;
        }
        public E getAnimal() {
            return animal;
        }} class Animal{
    } class Cat extends Animal {
    } class Dog extends Animal {
    }public class Generic{
    public static void main ( String [] args ){
         AnimalHouse<Animal> house1 = new AnimalHouse<Cat>();  AnimalHouse<Dog> house2 = new AnimalHouse<Animal>();         AnimalHouse<?> house3 = new AnimalHouse<Cat>();
             house3.setAnimal(new Cat());         AnimalHouse house4 = new AnimalHouse();
             house4.setAnimal(new Dog());
    }
    }编译这个会有很多说类型不兼容
    原因是虽然Cat 和 Dog 是Animal的子类,但是AnimalHouse<Dog> AnimalHouse<Cat>不是AnimalHouse<Animal>的子类.理解这句话是关键这样是有原因的,java tutorial 上举例说
    // A cage is a collection of things, with bars to keep them in.
    interface Cage<E> extends Collection<E>;interface Lion extends Animal {}
    Lion king = ...;interface Butterfly extends Animal {}
    Butterfly monarch = ...;Cage<Animal> animalCage = ...;
    animalCage.add(king);//这里和你本身的例子有点像了
    animalCage.add(monarch);//这两行都有问题,通不过编译解释说,这个cage是用来装所有的aniamls的,所以一个装狮子的笼子总不能用
    来装蝴蝶吧?
    所以在你的例子中,Animal是dog的父类,但是List<? super Dog>装的是dog的所有的父类,所以出现了"用装狮子的笼子总不能用来装蝴蝶"的错误了至于非比喻的解释就等高人回答了
      

  2.   

    那既然这样的话 我用add(new dog())他就能编译那这比喻又怎么解释,等待高人~~~
      

  3.   

    <? super Dog> 这个通配符限定为Dog的所有超类,所以不能因为泛型参数类型的继承关系(<Animal> and <Dog>)而推导出类本身的继承关系(Animal and Dog)。
      

  4.   

    C_program_Baby() 只要类型参数相同就可以了,都改成 Animal 也行。
      

  5.   

    其实是一个向上转型的问题(Upcasting)
    JAVA只有向上转型
    例子:
    class A {}
    class B extends A {}可以这样 A b = new B()
    但是不能 B a = new A();为什么java编译器只能向上转型,因为子类向上转型为父类时,用父类的方法的方法名一定在子类中存在。调用的时候不会出现 生成的对象 没有的方法。
    而如果用子类承载父类,子类的部分方法可能时父类没有的,所以其中就有可能出错。并且当用父类承载子类的时候,并不是调用父类的方法,java通过函数动态绑定的机制,会找到正确的方法执行。向上转型最实现多态很有帮助。
      

  6.   

    这段代码肯定是通不过的,你把泛型和继承搞混了,仔细的去看看泛型的说明。
    试想一下
    static void fun(List<? super Dog> o){o.add(new Animal());}
    这个表示为对象里放的是Dog及其子类,但你在代码里却放的是Animal,假设另一个叫Bird的Animal也放了进去,这样的java就不能保证这个o对象是放的还是Dog了,这和泛型的目标就矛盾了。
      

  7.   

    看错了,没有注意是super关键字的。变成super关键字后,这个问题就变得复杂了,要解释真有点难度。
    首先我们要理解java的泛型的类型安全性主要还是由编译器来完成的。因此对于这个编译出错的问题还是要从编译器能否在编辑期间确定集合里放的是什么类型。
    static void fun(List<? super Dog> o){o.add(new Animal());}
    在这个方法里,编译器只能判断的出来o里放的是Dog的超类,不能判断o里放的就是Animal,因些肯定会出现编译出错,这个时候如果放Animal进去的话,就会造成类型安全的问题。但如果把o.add(new Animal());修改为o.add(new Dog());就没有问题。因为Dog是唯一确定的,不会引起歧义,换句话说,Dog在继承树的最底层,肯定是满足o集合里的类型。
    为了便于理解,举个如果不是Dog会打破类型安全规则的例子。从下面的例子可以看出假设编译器对上面的代码报错的话,下面的代码应该也不报错。但实际上它的类型是不正确的。import java.util.*;
    class Generic
    {
    public static void main(String[] args)
    {
    List<Foo> list=new ArrayList<Foo>();//这个也满足List<? super Dog>
    fun(list);
    }
    static void fun(List<? super Dog> o){o.add(new Animal());}
    }interface Foo {
    }class Dog extends Animal implements Foo{
    }class Animal{
    }class Test implements Foo{}
      

  8.   

    List<Foo> list=new ArrayList<Test>()更容易理解。
      

  9.   

    呵呵,犯了个低级错误, List<Foo> list=new ArrayList<Test>();
    这是不对的,应该是这样。
    List<Foo> list=new ArrayList<Foo>();
    list.add(new Test());