Java基础(7-泛型)
类型擦除
1 | List list = new ArrayList(); |
Java 集合有个缺点:把一个对象“丢进”集合里之后,集合就会“忘记”这个对象的数据类型,当再次取出该对象时,该对象的编译类型就变成了 Object 类型,还需要进行强制类型转换。从 Java 5 开始,Java 引入了“参数化类型”的概念,允许程序在创建集合时指定集合元素的类型,Java 的参数类型被称为泛型。例如:List < String > 只能保存 String 类型的对象
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉。例如:在代码中定义的 List < Object >、List < String > 等类型,在编译之后都会变成 List。在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 < T > 则会被转译成普通的 Object 类型,如果指定了上限如 < T extends String > 则类型参数就被替换成类型上限
1 | List<Integer> list = new ArrayList<>(); |
为什么泛型的实现是类型擦除?
主要原因是为了向下兼容,即兼容 Java5 之前的编译的 class 文件,例如:Java1.2 上正在跑的代码可以在 Java5 的 JRE 上运行
常用的通配符
- ?:表示不确定的 Java 类型
- T(type):表示具体的一个 Java 类型
- K V(key value):分别代表 Java 键值对中的 Key Value
- E(element):代表 Element
限定和非限定通配符
- extends T> 通过确保类型必须是 T 的子类来设定类型的上界
- super T> 通过确保类型必须是 T 的父类来设定类型的下界
List <? extends T> 和 List <? super T> 的区别
-
List <? extends T> 可以接收任何继承自 T 的类型的 List,通常用于读取操作,确保可以读取为 T 或 T 的子类的对象
-
List <? super T> 可以接收任何 T 的父类构成的 List,通常用于写入操作,确保可以安全地向泛型集合中插入 T 类型的对象
注意:Array 不支持泛型,要用 List 代替 Array,因为 List 可以提供编译器的类型安全保证,而 Array 却不能
1 | public void process(List<? extends Number> list) { |
PECS原则
- Producer Extends:如果某个对象提供数据(即生产者),使用extends(上界限定符)
- Consumer Super:如果某个对象使用数据(即消费者),使用super(下界限定符)
协变和逆变
- 协变:子类型可以替换父类型
1 | class Animal {} |
- 逆变:父类型可以替换子类型
1 | class Animal {} |
使用案例
泛型类
1 | //此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型 |
泛型接口
1 | public interface Generator<T> { |
泛型方法
1 | public static <E> void printArray(E[] inputArray) { |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 爱编程的小生!
评论