泛型通配符:
例子:
interface AA{}
class BB{}
class A1 extends BB implements AA{}
class B1 extends A1{}
List<? extends BB> list = new ArrayList<A1>();
//list.add(new A1()); A1继承BB,但这里会编译报错The method add(capture#1-of ? extends BB) in the type List<capture#1-of ? extends BB> is not applicable for the arguments (A1)
List<? extends BB> list0 = new ArrayList<B1>();
list = list0;
解析:
list.add(new A1())之所以报错是因为不能确定list中的元素是什么类型,虽然此时它的确指向的是new ArrayList<A1>(),但编译器还没有智能到这种程度,知道list当前的元素类型。
List<? extends BB>只是一种引用声明,声明引用的List中的元素类型是继承BB的,但并不确定是何种类型(capture#1-of ? extends BB),所以list = list0并不会报错,
因为list和list0当中的元素都是继承BB的,符合(capture#1-of ? extends BB)的定义声明
List<? super B1> list2 = new ArrayList<A1>();
List<? super A1> list3 = new ArrayList<BB>();
//list3 = list2; //编译报错 Type mismatch: cannot convert from List<capture#2-of ? super B1> to List<? super A1>
list2 = list3;
解析:list2不能添加A1类型元素,因为A1是B1的父类,而list3可以添加A1类型元素,因此将list2赋给list3不正确。(add只能add与super同等级的或者为该等级子类的类型,尽管B1的直接超类就是A1,也不能添加A1类元素,只能认为编译器认为B1有可能实现不同的接口,譬如I1,单I1跟A1是没有继承关系的,所以如果集合是I1类型,那添加A1类型的元素肯定是错的)
list2=list3似乎有些别扭,因为list2的元素类型是super B1,即它可能是A1,而list3的元素类型是super A1,即它可能是BB,而将list3赋给list2似乎是将父类元素BB强转为A1,
这应该是报错才对,但我们要回到之前讨论的List<? super B1> 的意义是什么,它只是一种引用声明,声明引用的List的元素类型是super B1的(capture#1-of ? super B1),
至于是什么类型并不确定,它可以动态指向任何元素类型super A1的List。以下赋值声明也正确:
List<? super B1> list4 = new ArrayList<BB>(); //BB是B1的祖辈元素
List<? super B1> list2 = new ArrayList<A1>();
//list2.add(new A1()); 编译报错The method add(capture#1-of ? super B1) in the type List<capture#1-of ? super B1> is not applicable for the arguments (A1)
解析:
list2的元素实体明明是用了装A1类型的,但添加A1却报错,这是因为List<? super B1>也可能指向new ArrayList<B1>(),此时直接添加父类元素A1当然报错了
总结:
1.List<? super AA> list2 = new ArrayList<AA>();//List<? super AA> list2 = new ArrayList<B1>();这个声明会报错
2.list2.add(new B1());
1和2要的时机是不同的,1是声明,2是往堆内存添加实际对象。
声明时创建的集合泛型类型要直接符合通配符的父子声明;
添加时看是否会存在一种符合通配符的类型A(不用看实际指向的堆内存存的是什么类型的数据),添加的元素类型与类型A不兼容,若无则可添加该类型元素。