一、什么是泛型
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
1.为什么需要泛型
- 1.1 一个例子
List arrayList = new ArrayList();
arrayList.add("aaaa");
arrayList.add(100);
for(int i = 0; i< arrayList.size();i++){
String item = (String)arrayList.get(i);
System.out.println(item);
}
类型转换异常
ArrayList可以存放任意类型,在上面同时存入两个不同类型的值,在使用下标获取值,若不能强转,则编译阶段不会报错,运行阶段反之
- 1.2 解决
给容器定义一个泛型,指定传入的参数类型
ArrayList<Integer> list = new ArrayList<>();
2.类型擦除
java 的泛型是伪泛型,这是因为 Java 在编译期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除 。【传不同的泛型,实际类型相等】
2.1定义了两个ArrayList数组,
一个是ArrayList<String>泛型类型的,只能存储字符串;
一个是ArrayList<Integer>泛型类型的,只能存储整数
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);
结果为true,说明泛型类型String和Integer都被擦除掉了,只剩下原始类型。
- 2.2 使用反射添加其他类型的元素
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
//这里直接添加会报错,因为泛型类型的实例为 Integer
//list.add("a");
//通过反射添加
list.getClass().getMethod("add", Object.class).invoke(list, "asd");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
泛型实例在编译之后被擦除掉了,只保留了原始类型。
3.泛型的使用
泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法
- 3.1泛型类
//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Generic<T>{
private T key;
public Generic(T key) {
this.key = key;
}
public T getKey(){
return key;
}
}
实例化泛型类
Generic<Integer> genericInteger = new Generic<>(123456);
- 3.2泛型接口
public interface Generator<T> {
public T method();
}
实现泛型接口时,可以指定类型也可以不指定
- 3.2.1实现泛型接口,不指定类型:
class GeneratorImpl<T> implements Generator<T>{
@Override
public T method() {
return null;
}
}
- 指定类型
class GeneratorImpl<T> implements Generator<String>{
@Override
public String method() {
return "hello";
}
}
- 3.3泛型方法
public static < E > void printArray( E[] inputArray )
{
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
4.使用泛型注意的问题
- 4.1 自动类型转换
因为类型擦除的问题,所以所有的泛型类型变量最后都会被替换为原始类型。
既然都被替换为原始类型,那么为什么我们在获取的时候,不需要进行强制类型转换呢
- 4…2泛型类型变量不能是基本数据类型
就比如,没有ArrayList,只有ArrayList。因为当类型擦除后,ArrayList的原始类型变为Object,但是Object类型不能存储double值,只能引用Double的值。
- 4.3编译时集合的instanceof
if( arrayList instanceof ArrayList) {}//编译错误
- 4.4泛型在静态方法和静态类中的问题
泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数,因为泛型类中的泛型参数的实例化是在定义对象的时候指定的,
而静态变量和静态方法不需要使用对象来调用。对象都没有创建,不能确定这个泛型参数是何种类型,所以当然是错误的
这种情况不包括泛型方法
5.通配符
- ? 表示不确定 的类型,通常用于泛型方法的调用代码和形参,不能用于定义类和泛型方法。
- T (type) 表示具体的一个 java 类型
- K V (key value) 分别代表 java 键值中的 Key Value
- E (element) 代表 Element
- 上界通配符 < ? extends E> 表示这个泛型中的参数必须是 E 或者 E 的子类
- 下界通配符 < ? super E> 表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至 Object