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确定了泛型的下界。