泛型
泛型不允许直接 new
泛型特点:
- 泛型就是编写模板代码来适应任意类型
- 使用时不必对类型进行强制转换
- 通过编译器对类型进行检查
- 使用泛型的类型支持向上转型
- 泛型实现方式是擦拭法
- 泛型通常适用于集合中
泛型主要应用于集合中
泛型的定义
class Person<T, E>{}
支持类定义多个泛型
PS: 静态方法定义的泛型和类上的泛型没有任何关系
泛型的实例
public class Person<T>{
public T field ;
public void setField(T field){
this.field = field ;
}
public T getField(){
return this.field ;
}
public static <E> Person<E> build(){
return new Person<E>() ;
}
}
擦拭法
- 概念:
所谓擦拭法是指,虚拟机对泛型其实一无所知,所有的工作都是编译器做的 - 编译器内部永远把所有泛型 T 视为Object处理
- 泛型不支持基本类型、因为 Object 无法持有基本数据类型
- List#getClass() == List#getClass()
同类型使用不同的泛型, 类对象相同 - 泛型 T 不能直接 new ,因为会解释成 new Object()
可以借助反射
Class clazz ;
clazz.newInstance();
泛型的继承
- 定义方式
class Student extends Person {}
注意: 父类的泛型是 真实类型
这里是使用父类的泛型,必须是真实类型 - // 子类获取 父类 定义的真实泛型 类型
Class clazz = this.getClass();
// 获取当前类的带泛型父类
Type type = clazz.getGenericSuperclass();
// 判断 父类 是否是 参数化父类(带泛型)
if (type instanceof ParameterizedType) {
// 获取 父类 的泛型类型(可能有多个)
Type[] types =((ParameterizedType)type).getActualTypeArguments();
// 获取 父类的泛型类型
Class clz = (Class)types[0] ;
}
extends通配符
- 作用:
Person<? extends Number>
生产者、可以做读操作 - Person<? extends Number> p = new Person<>()
p.setField(<? extends Number>)
super通配符
- 作用:
Person<? super Integer>
消费者、可以做写操作 - Person<? super Integer> p = new Person(10)
p.getField() 返回 ? super Integer, 只能用Object接收