Java泛型-概念
1. 什么是Java泛型?
Java泛型是JDK 5 中引入的一种编程语言特性,它允许在编写代码时使用参数化类型。泛型的主要目的是提高代码的灵活性和重用性,同时在编译时提供更强的类型检查。
泛型具有以下优点:
- 编译时的强类型检查
- 避免了类型转换
- 泛型编程可以实现通用算法
1 | |
以上例子在未使用泛型的情况下,list1中存放的是Object类型,在从list1中获取i1时需要进行强制类型转换,如果在list1中不小心放入了String类型,程序在运行中会抛出异常;
在使用泛型后,list2中只能存放String类型,如果往list2中放入Integer类型,在编写和编译代码时就能依赖JVM的强类型检查尽早发现错误。
2. 泛型的基本使用
2.1 泛型类
泛型类的声明
1 | |
泛型的类型只能是类,不能是基本类型
2.2 泛型接口
泛型接口的声明
1 | |
2.3 泛型方法
泛型类中使用泛型方法
1 | |
非泛型类中使用泛型方法
1 | |
静态方法上使用泛型
1 | |
2.4 泛型的上界、下界
在使用泛型的时候,我们可以为传入的泛型类型实参进行上下边界的限制。
泛型上界:传入的类型实参必须是指定类型或者指定类型的子类型
1 | |
List<? extends T>是被设计用来读取数据的泛型,并且只能读取类型为T的元素。如果要满足List<? extends T>能添加元素,需满足List中的任何一个元素都能被转换为T的子类,所以List<? extends T>不能用来写入元素。
泛型下界:传入的类型实参必须是指定类型或者指定类型的父类型
1 | |
List<? super T>是被设计用来存储数据的,只能添加T类型或其子类类型。因为List中的任何一个元素都能向上转型为T类型或者T的父类型。
PECS
PECS是”Producer Extends,Consumer Super”(生产者用Extends,消费者用Super)的缩写。
- “Producer Extends”的意思是,如果需要一个List去生产T类型的数据(需要从List中读取T类型实例),就声明List中的元素为
<? extends T>,例如List<? extends Integer>,但是不能往里面添加元素。 - “Consumer Super”的意思是,如果需要一个List去消费T类型的数据(需要往List中添加T类型实例),就声明List中的元素为
<? super T>,例如List<? super Integer>。但是不能保证从这个List中读取出来的数据类型。
2.5 无界通配符与向上转型
向上转型是指用子类实例去初始化父类,这是面向对象中多态的重要表现。
语法形式:<?>,不依赖于类型参数的泛型,不能添加数据,示例如下:
1 | |
泛型不能向上转型,但是可以通过使用通配符来向上转型
1 | |
2.6 泛型数组
1 | |
3. 深入理解Java泛型
3.1 泛型擦除
Java的泛型实现采取了“伪泛型”的策略,即语法上支持泛型,但是在编译阶段会进行“类型擦除”,将所有的泛型表示(尖括号中的内容)都替换为具体的类型。
类型擦除的方式:
删除类型参数声明,即删除<>的部分
根据上下界推断,将泛型类型替换为具体类型:如果是无界通配符(?)或者无上下界限制则替换为Object;存在上下界限制时则替换为限制的类型
插入强转换代码
1
2
3class Box<T> { T data; } ==> class Box { Object data; }
class Box<T extends Number> { T data; } ==> class Box { Number data; }
class Box<T super Number> { T data; } ==> class Box { Number data; }
3.2 泛型和反射
泛型的实例化
因为泛型不存在Class文件,所以泛型不能直接实例化;但是可以通过反射进行实例化1
2
3T obj = new T(); // 错误
Class<T> clazz;
T obj = (T) clazz.newInstance(); // 正确