1 概念
JDK1.5中引入了泛型的的概念,泛型的本质是“参数化类型”,在类型参数在使用(如继承或实现接口)时确定。
泛型可以在编译期进行类型安全检测。
Java泛型是在编译器这个层次实现的,字节码中是不包含泛型中的类型信息的。编译器在编译时去掉泛型,称为类型擦除。
2 泛型方法
泛型方法的格式为在方法的修饰符后面添加泛型标记<E>
,使得方法被调用时可以接收不同类型的参数。
public static <E> List<E> arrayToList(E[] arr) {
ArrayList<E> list = new ArrayList<>();
for (E e : arr) {
list.add(e);
}
return list;
}
注意:
- 泛型方法可以在任何类中使用,在泛型类中使用时,泛型方法的泛型参数
E
和泛型类的T
是没有关系的。 - 泛型方法可以声明为
static
方法,因为泛型参数是在调用该方法时确定的,不是在实例化类时确定的。
3 泛型类
在类名后面添加泛型参数的声明<T>
.
- 泛型参数可以作为非静态属性的类型,非静态方法的参数类型,非静态方法的返回值类型,但在静态方法中不能使用类的泛型。
原因:静态方法在类加载的准备阶段就完成,而泛型参数的确定是在实例化对象的时候。 - 不能使用
new T[len]
,可以使用T[] arr = (T[]) new Object[len];
4 类型通配符
?
可以替代具体的参数类型,逻辑上List<?>
是所有List<具体类型参数>
的父类。<? extends T>
表示该通配符只能匹配T
以及它的子类<? super T>
表示该通配符只能匹配T
和它的父类
主要特点:
-
<? extends T>
属于 get first, 主要用于查看数据,如List<? extends T>
类型的对象如果使用add(T e)
方法,编译期报错,因为赋值操作后,集合中并没有限定泛型的类型,而是通过<capture#1-of ? extends T>
占位符表示捕获了一个 T 或 T 的子类,具体类型未知,所以不能使用add()
-
<? super T>
属于 put first, 主要用于频繁加入数据的场景,也可以用于获取数据,但需要强制类型转换(默认返回 Object 类型)
class Animal {}
class Cat extends Animal {}
class Garfield extends Cat {}
public class Test {
public static void main(String[] args) {
// 基本的 List 集合
List<Animal> animals = new ArrayList<>();
List<Cat> cats = new ArrayList<>();
List<Garfield> garfields = new ArrayList<>();
// 简单添加数据
animals.add(new Animal());
cats.add(new Cat());
garfields.add(new Garfield());
// ? extends T 类型通配符
List<? extends Cat> extendsCatFromCat = cats;
// get 操作正常,且返回类型为 T 满足多态
Cat cat = extendsCatFromCat.get(0);
// add() 编译错误
extendsCatFromCat.add(new Cat());
// ? super T 类型通配符
List<? super Cat> superCatFromCat = cats;
// 正常添加数据,必须是 Cat 或 Cat子类
superCatFromCat.add(new Cat());
superCatFromCat.add(new Garfield());
// get 要强制类型转换
Cat c = (Cat) superCatFromCat.get(2);
}
}