Java中的泛型,只在编译阶段有效.在编译过程中,正确检验泛型的结果后,会将泛型的相关信息擦出,并且
在对象进入和离开方法的边界处添加类型检查和类型转换的方法.
类型通配符
什么是类型通配符?
类型通配符一般是使用"?"代替任意的类型实参。
所以,类型通配符是类型实参,而不是类型形参(泛型标识符)。
类型通配符的上限
●语法
类/接口<? extends 实参类型>
要求该泛型的类型,只能是实参类型,或实参类型的子类类型
上限不能填充元素 取出的元素类型是实参类型
List <? extends Fruit> list = new ArrayList();
理解:new ArrayList创建对象,未指定泛型实参,所以泛型在编译期被擦除为Object,在操作的时候Object会被转换成上限类型Fruit。在对list进行set操作的时候,被设置的元素的类型不一定小于等于实际的泛型类型,对new出的ArrayList的确定和访问是通过list引用的类型来的,也就是说实际对象的泛型只能确定为Fruit或Fruit的子类。但是这个限制对于set来说还不够,因为java类型可以自动向上转换,但是向下转换就需要强制转换。对于get,则可以确定取出的元素类型一定是Fruit或Fruit的子类。所以,下界通配符适合作为生产者,而上界通配符适合作为消费者。
类型通配符的下限
●语法类/接口<? super 实参类型>
要求该泛型的类型,只能是实参类型,或实参类型的父类类型。
下限可以填充实参类型或实参类型的子类,取出的元素类型是Object类型
List <? super Fruit> appList = new ArrayList();
泛型擦除
泛型信息只存在于代码编译阶段,在进入JVM之前(编译结束,生成字节码文件),与泛型相关的信息会被擦除掉,我们称之为类型擦除
无限制类型擦除 (泛型类型没有指定具体类型,用Object作为原始类型;)
public class Erasure<T>{
public T key;
public T getKey(){return key;}
public void setKey(T key){this.key= key;}}
===>
public class Erasure{
public Object key;
public Object getKey(){return key;}
public void setKey(Object key){this.key= key;}}
有限制类型擦除 擦除为上限类型
public class Erasure<T extends Number>{
public T key;
public T getKey(T t){return key;}
public void setKey(T key){this.key= key;}}
===>
public class Erasure{
public Number key;
public Number getKey(){return key;}
public void setKey(Number key){this.key= key;}}
擦除方法中类型定义的参数
public <T extends Number> T getValue(T value) {return value;}
==>
public Number T getValue(Number value) {return value;}
桥接方法
interface Info<T>{T info(T var);}
class InfoImpl implements Info< Integer>{
@Override public Integer info(Integer var){return var;}
}
==>
interface Info{Object info(Object var);}
class InfoImpl implements Info{
public Integer info(Integer var){return var;}
//桥接方法,保持接口和类的实现关系
@Override public Object info(Object var){return info((Integer)var);}
}
对传泛型实参的限制
public class Box<T extends Number> {