泛型是一种“代码模板”,可以用一套代码套用各种类型。
1、泛型
定义类、接口、方法时,同时声明了一个或者多个类型变量(如:< E >),称为泛型类、泛型接口,泛型方法。
如:
public class ArrayList<E> {
...
}
// 使用
ArrayList<Person> list1 = new ArrayList<Person>();
list1.add(new Person("Tom"));
ArrayList<String> list2 = new ArrayList<>();
list2.add("CSDN");
作用:泛型提供了在编译阶段约束所能操作的数据类型,并自动进行检查的能力。这样可以避免强制类型转换,及其可能出现的异常。
本质:把具体的数据类型作为参数传给类型变量。
2、自定义泛型
自定义泛型类:
修饰符 class 类名<类型变量, 类型变量, ...> {
...
}
自定义泛型接口:
修饰符 interface 接口名<类型变量, 类型变量, ...> {
...
}
自定义泛型方法:
修饰符 <类型变量, 类型变量, ...> 返回值类型 方法名(形参列表) {
...
}
栗子:
public class Pair<T> {
private T first;
private T last;
public Pair(T first, T last) {
this.first = first;
this.last = last;
}
public T getFirst() { ... }
public T getLast() { ... }
// 静态泛型方法应该使用其他类型区分:
public static <K> Pair<K> create(K first, K last) {
return new Pair<K>(first, last);
}
}
3、通配符 & 上下限
- “?”,可以在“使用泛型”的时候代表一切类型;E T K V 是在定义泛型的时候使用。
- 泛型上限:? extends Person:?能接收的必须是Person 或者其子类。
- 泛型下限:? super Person:?能接收的必须是Person 或者其父类。
4、泛型的擦除 & 注意事项
泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。
泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。