泛型通配符
上一节讲到,泛型是不变的,可有时候需要实现协变,在两个类型之间建立某种类型的向上转型关系,应该使用通配符.
概览
泛型通配符有三种:
- ? 任意类型,如果没有明确,那么就是Object以及任意的java类
- ? extends E 向下限定,E及其子类
- ? super E 向上限定,E及其父类
? 通配符
首先定义两个类
class Person{
public void say(){
System.out.println("person say hi!!");
}
}
class Student extends Person{
@Override
public void say() {
System.out.println("student say hi!!");
}
}
@Test
public void testArrayList(){
ArrayList<?> list = new ArrayList<>();
list.add("helo");
}
上面的代码,看上去就是对"?"通配符的使用,而且看起来并没有任何逻辑问题,定义一个任意类型的泛型,然后添加String类型的值,但是list.add("helo");会报错,list不能添加数据,因为"?"通配符不是这么使用的.
泛型通配符不是用在定义对象上,而是用在方法形参上.
@Test
public void testArrayList(){
ArrayList<Student> list = new ArrayList<>();
list.add(new Student());
method(list); //可以传入Student的类型
ArrayList<Person> list2 = new ArrayList<>();
list2.add(new Person());
method(list2); //可以传入Person的类型
}
public static void method(ArrayList<?> list){ //定义泛型通配符 ,这个方法可以传入任意类型的泛型.
for (Object o : list) {
System.out.println(o);
}
}
? extends E
? extends E 是上界限定,限定了天花板,只能是E及其子类
@Test
public void testExtendArray(){
ArrayList<Person> list1 = new ArrayList<>();
list1.add(new Person());
method2(list1); //method2中传入Person类的实例,没有问题
ArrayList<Student> list2 = new ArrayList<>();
list2.add(new Student());
method2(list2); //method2中传入Student类的实例,也没有问题,因为Student继承Person
ArrayList<Object> list3 = new ArrayList<>();
list3.add("");
method2(list3); //这里就会出错,因为Object不是Person的子类,所以不能这样使用. //error
}
public static void method2(ArrayList<? extends Person> list){ //这里就是接受Person及其person子类对象的list
for (Person person : list) {
System.out.println(person);
}
}
? super E
? super E 是下界限定,限定为E及其父类
@Test
public void testSuperArrayList(){
ArrayList<Person> list = new ArrayList<>();
list.add(new Person());
method3(list); //传入Person类型的ArrayList 没有问题
ArrayList<Object> list2 = new ArrayList<>();
list2.add("");
method3(list2); //传入Object类型也没有问题,因为Object是Person的父类
ArrayList<Student> list3 = new ArrayList<>();
list3.add(new Student());
method3(list3); // error 在这里就会出错,是因为Student不是Person的父类
}
public static void method3(ArrayList<? super Person> list){ //这里限定为Person及其父类
for (Object o : list) {
System.out.println(o);
}
}