泛型通配符
在java泛型中,? 表示通配符,代表未知类型,< ? extends Object>表示上边界限定通配符,< ? super Object>表示下边界限定通配符。
?通配符与T的区别
T:主要用于泛型接口,类,方法定义的时候,作用只是将参数泛型化(类方法的定义)。
?:主要用于实例化对象的时候,当我们实例化对象,不确定泛型参数的具体类型的时候,可以使用通配符进行对象从属范围定义。
< T > 等同于 < T extends Object>
< ? > 等同于 < ? extends Object>
例如:定义泛型类
//在实例化泛型类时,必须指定V的具体类型
//此处V可以写成任意符合java规则的标识
class GenericValue <V>{
//value这个成员变量的类型为V,V的类型由外部指定
private V value;
//泛型构造方法,形参v的类型由该类具体使用时指定。
public GenericValue(V v){
this.value = v;
}
//泛型方法 返回值由该类具体使用时指定。
public V getValue(){
return value;
}
}
例如实例化泛型对象:
List<? extends Number> nList = null;
nList = new ArrayList<Integer>();
nList = new ArrayList<Long>();
说明这时候 nList可以指向任何以数值实例化的List集合。
上界类型通配符(?extends)
List<? extends Number> nList = null;
nList= new ArrayList<Integer>();
Number numObject = nList.get(0); //语句1,正确
Integer intObject = nList.get(0); //语句2,错误
nList.add(new Integer(1)); //语句3,错误
语句1:List<? extends Number>nList存放Number及其子类的对象,语句1取出Number(或者Number子类)对象直接赋值给Number类型的变量是符合java规范的(父类可以指向子类对象)。
语句2:List<?extends Number>nList存放Number及其子类的对象,语句2取出Number(或者Number子类)对象直接赋值给Integer类型(Number子类)的变量是不符合java规范的(子类不可指向父类对象)。
语句3:List<? extends Number>nList不能够确定实例化对象的具体类型,因此无法add具体对象至列表中。
总结:上界类型通配符add方法受限,但可以获取列表中的各种类型的数据,并赋值给父类型(extends Number)的引用。因此如果你想从一个数据类型里获取数据,使用 ? extends 通配符。限定通配符总是包括自己
下界类型通配符(? super )
List<?super Number> list1 = new ArrayList<Number>();
// Number integergs = list1.get(0);
list1.add(1);//语句1正确
list1.add(2.0f);//语句2正确
Number nubmer = list1.get(0);//语句3错误
Integer iNumber = list1.get(0);//语句4错误
语句1:当使用下界类型通配符的时候,可以向集合中放任何Number类型或其子类。
语句2:同语句1。
语句3:当使用下界类型通配符,不可以用Number类及其基类去承接获取的元素,只能用Object类去承接。
语句4:同语句3。
总结:
**如果要从集合中读取类型T的数据, 并且不能写入,可以使用 上界通配符(<?extends>)—Producer Extends。
如果要从集合中写入类型T 的数据, 并且不需要读取,可以使用下界通配符(<? super>)—Consumer Super。**