之所以需要泛型通配符,具体原因首先让我们看下,首先定义一个父类Animal如:
public class Animal {
private String type;
public Animal(String type) {
this.type = type;
}
public void show() {
System.out.println("type = " + type);
}
}
定义一个子类Cat:
public class Cat extends Animal{
public Cat(String type) {
super(type);
}
}
定义一个字类Dog:
public class Dog extends Animal{
public Dog(String type) {
super(type);
}
}
编写测试类就会发现一个问题,但是只是使用泛型类的情况,代码跟报错信息如:
package com.test.cgb;
import java.util.ArrayList;
import java.util.List;
public class GenericDemo {
public static void main(String[] args) {
List<Animal> animals = new ArrayList<>();
animals.add(new Animal("动物"));
List<Cat> cats = new ArrayList<>();
cats.add(new Cat("布偶猫"));
cats.add(new Cat("英杰猫"));
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog("金毛"));
dogs.add(new Dog("拉布拉多"));
/**
* 下面之所以报错是因为:
* 泛型子类型
* A--一个类或者一个接口
* B--A的字类或者子接口
* G--泛型类或者泛型接口
* G<B>不是G<A>的子类型,其实二者没有任何关系。所以比如List<Animal>的字类不是List<Cat>
*/
GenericDemo.showAnimalUserGeneric(animals);
/**
* 执行这两个方法GenericDemo.showAnimalUserGeneric(cats);
GenericDemo.showAnimalUserGeneric(dogs);就会报错
* 报错信息为:The method showAnimalUserGeneric(List<Animal>) in the type GenericDemo is not applicable
* for the arguments (List<Cat>)
*/
GenericDemo.showAnimalUserGeneric(cats);
GenericDemo.showAnimalUserGeneric(dogs);
}
// 使用泛型的情况
public static void showAnimalUserGeneric(List<Animal> list) {
for (int index = 0; index < list.size(); index ++) {
Animal animal = (Animal) list.get(index);
animal.show();
}
}
}
于是需要使用通配符来解决这个问题:
类型通配符,用来匹配类型实参如使用List<?>匹配List<Animal>,也就是在编译时获取到Object类型:

但是单独List<?>还有个缺点就是无法对传入的参数类型进行限制,因为这个showAnimalUserGeneric(List<?> list)方法是可以接收字符串的,这个在编译器是不会报错的,但是在运行期Animal animal = (Animal)list.get(index)时String就会无法转换成Object类型,就会报错的。所以需要使用List<? extends Animal>,这样可以限制参数类型例如没有使用List<? extends Animal>之前是这样的:

泛型通配符上线:接着就是使用了List<? extends Animal>
语法<? extends 类或接口(1个)>表示?能匹配的类型要么是指定的类或接口,要么是其子类或子接口:

泛型通配符下线:
语法List<? super 类或接口(1个)>表示?能匹配的类型要么是指定的类或接口,要么是其父类或父接口:
浙公网安备 33010602011771号