泛型(Generic Type)
- 允许在定义接口、类、方法时使用类型形参,类型形参在整个接口、类体、方法内可当成类型使用,这个类型形参将在声明变量、创建对象、调用方法时动态地指定(即传入实际的类型参数,类型实参)
- 传入实际的类型参数不能是基本数据类型
- 同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的
- 编译器会将泛型代码转换为普通的非泛型代码(使用强制类型转换)
- 常见的类型形参:T、E、K、V 等
- 泛型的意义和作用
- 类型的参数化,可以把类型像方法的参数那样传递
- 泛型使编译器可以在编译期间对类型进行检查以提高类型安全,减少运行时由于对象类型不匹配引发的异常
- 在接口、类后增加尖括号,尖括号里放一个数据类型,代表类型形参
- 在创建带泛型声明的自定义类中定义构造器时,不要增加泛型声明
- 定义实现类、子类时,使用带泛型声明的接口、父类时不能再包含类型形参,
- 如果使用带泛型声明的类时没有传入实际的类型参数,系统会把类 里的 T 形参当成 Object 类型处理
- 不管泛型的实际类型参数是什么,它们在运行时总有同样的类(class)
- 在静态方法、静态初始化块或者静态变量的声明和初始化中不允许使用类上定义的类型形参;instanceof 运算符后不能使用泛型类
- 泛型不存在继承的关系,如 Collection 不是 Collection 的子类型
- 在声明方法时定义一个或多个类型形参,放在方法修饰符和方法返回值类型之间
- 方法中的泛型参数无须显式传入实际类型参数,编译器会根据实参推断类型形参的值
修饰符 <T, S> 返回值类型 方法名(形参列表) {
//方法体
}
设定类型通配符的上限
- 设定类型形参的上限(至多有一个父类上限,可以有多个接口上限)
}
- 设定类型通配符的下限
- 擦除:当把一个带泛型的对象赋给一个不带泛型的变量时,所有在尖括号之间的类型信息都将被扔掉
- 堆污染:对于形参个数可变的方法,该形参的类型又是泛型时,容易导致“堆污染”@SafeVarargs 抑制堆污染警告的注解
List<Integer> li = new ArrayList<>();
li.add(123);
List list = li; // 泛型的擦除
List<String> ls = list; // 泛型的转换
// 当试图把 ls 里的元素当成 String 类型的对象取出时,将引发 ClassCastException 异常
// System.out.println(ls.get(0));
- 数组元素的类型不能包含类型变量或类型形参,除非是无上限的类型通配符