传递一个类型对象到泛型类型所引发的问题

 

 

1 class People{};
2 class Student extends People{};
3 class teacher extends People{};
4 //创建一个List,目的是将它用来存储所有继承自People基类的对象实例,但实际上我们无事可做!
5 List<? extends People> list = new ArrayList<Student>();    
6 //list.add(new Student());    //compile error
7 //list.add(new People());        //compile error
8 //list.add(new Object());        //compile error

从上面可以看出,无论我们是add一个基类实例还是派生类实例到list中都会发生编译错误,这是为什么呢?
我们看下面这个例子:
print(list.indexof(new Fruit())); //ok! return -1, the argument is Object
 
对比一下,我们发现add()接受一个具有泛型参数类型的参数,但是indexof将接受Object类型的参数。当我们创建一个List<? extends People>时,addd的参数也同步变成了<? extends People>.但是从这样的描述中,编译器并不能了解到这里到底需要People的哪个具体子类型,因此它不会接受任何类型的Fruit,甚至是Object类型。---因此,编译器直接拒绝 对参数列表中设计通配符的方法(比如:add())的调用. 
 

这就是这个compile eror的原因!
 
那么怎么解决这个问题呢? 我们可以使用超类型通配符,通过调用方法指定<? super Myclass>,甚至使用类型参数<? super T>,这样就可以安全的传递一个类型对象到泛型类型中了,这在java中称之为 “逆变”,

 1 static <T> void method1(List<? super T> list, T item){
 2         list.add(item);
 3 }
 4 static void test1(){
 5 List<Fruit> list = new ArrayList<Object>();
 6         method1(list, new Apple());
 7         method1(list, new Orange());
 8         list.add(new Blanla());    //一般用法
 9       for (Fruit fruit : list) {
10             println(fruit.getClass().toString());
11         }
12 }
13     
14 Output:
15 class demo5.Apple
16 class demo5.Orange
17 class demo5.Blanla                

 <? super Fruit>表示list所持有的类型为Fruit与Fruit的基类中的某一类型,以上面这个例子为例,Apple和Orange必定是这某一类型的子类,所以add方法能正确的被调用,从上面可以看出,extends定义了泛型的上界,而super确定了泛型的下界。

 

posted @ 2016-06-07 14:41  .天祈  阅读(2968)  评论(0编辑  收藏  举报