泛型的好处:
- 类型安全
- 消除强制类型转换
- 潜在的性能收益。
Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。
- 虚拟机中没有泛型,只有普通的类和方法
- 擦除时,所有类型参数都用他们的限定类型替换(默认为Object)
- 一般通过 桥方法 保持多态(在桥方法中,调用泛型类对应的重写方法)
注意事项:
- 不能用基本类型作为泛型:
擦除后Object不能存储基本类型数据, 但基本类型并不多,可以使用独立的类和方法特别处理
- 运行时类型查询只适用原始类型 :
同一个泛型类的两个对象即使泛型不同,getClass()返回的原始类型也相同
- 不能创建参数化类型的数组 :
擦除后,数组相当是 Object[],数组会记得元素类型,若尝试插入其他类型的元素,会弹出ArrayStoreException异常
但若尝试插入相同类下不同泛型的对象,则可以通过编译
Ps: 可以声明一个泛型数组,只是不能用new 方法初始化,可以声明通配类型的数组然后强制转换
eg: Pair
但仍然是不安全的,仍可以插入不同泛型的对象,如果对数组中不同泛型的对象调用方法,可能出现ClassCastException
- 如果需要收集参数化类型对象, 只有一种安全而有效的方法:使用 ArrayList: ArrayList
- 向参数个数可变的方法传递泛型类型实例,虚拟机实际上创建了一个泛型类型的数组,这与之前的规则冲突,会出现警告
如果我们确定传入参数类型正确,可以用注解的方式抑制警告
@SuppressWarnings("unchecked")
@SafeVarargs
但这种情况仍有隐患,擦除后的Object数组,仍不能识别出 对象是否为相同泛型,插入时仍不会报错,
但在实际使用时会出现异常。
- 不能实例化泛型的类型变量
以
public Pair() { first = new T(); second = new T(); } // 会有Error
因为T.class 是不合法的,如果想用反射Class.newInstance方法构造也是不允许的。
在JAVA 8 之后,可以让调用者提供一个构造器表达式,如:
// Supplier
public static Pair makePair(Supplier constr){
return new Pair<>(constr.get(),constr.get());
}
接下来就可以使用如下语句:
Pair p = Pair.makePair(String.class);
ps: Class类本身是泛型, String.class是 Class 的实例(也是唯一的实例)
- 不能构造泛型数组
在方法中,如果出现 T[] ts = new T[2]; 会报告Error ,因为在擦除后,都会转换为泛型的约束类型数组
- 不能在静态域或静态方法引用泛型
同样是擦除的原因,擦除后没有具体类型,就不能工作。
- 要注意擦除后的冲突
如果有和Object类相同名字的方法,在擦除后会出现两个一样的方法,而出现错误。
ps: 如果父类实现了一个带泛型的接口,子类不能再实现 带泛型的该接口。
泛型与继承的关系
- 假设有 Father , Son 两个类,并且Son类为Father类的子类。
当二者作为泛型时,相应的对象之间没有联系, 如Pair
- 要解决上述情况,希望可以建立联系,可以用通配符 Pair extends Father>
但若是 Pair中有参数为泛型类型的 方法,在通配符的对象中,就会因为无法匹配通配符而出错。
假设存在一个方法 void setSon(Son); 如果使用了通配符,就会变成 void setSon(? extends Father);就会出现 compile-time error
而如果是一个无参方法返回通配类型,则不会出现问题 : ? extends Father getSon();
- 通配符的另一个用法
Pair< ? super Son> 表示可以匹配Son以及Son的所有父类
泛型Class类
java.lang.Class
T newInstance() 返回无参构造器构造的一个新实例
T cast(Object obj) 如果obj为NULL或者有可能转换为T,则返回obj,否则抛出 BadCastException
T[] getEnumConstants() 如果T是枚举类型,则返回所有值组成的数组,否则返回NULL
Class super T> getSupercalss() 返回这个类的父类,如果T不是类或为Object,则返回NULL
Constructor
Constructor
T newInstance(Object...parameters) 返回用指定参数构造的新实例