「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战」
什么是泛型?
Java泛型( generics) 是JDK 5中引⼊的⼀个新特性;
在定义类、接口、方法的时候使用类型参数,在使用的时候替换成具体的类型;
泛型广泛应用在集合类框架中;
好处:
可以在编译前进行参数类型检测;
可以提高代码的复用性,以 List接口举例
需要有存放 String和 Integer的 List,如不⽤泛型, 存放String类型要写⼀个List接口, 存放Integer要写另外⼀个List接口, 泛型可以很好的解决这个问题。
代码中的泛型
泛型类
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
复制代码
泛型接口
public interface List<E> extends Collection<E>
复制代码
泛型方法
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
复制代码
泛型的参数类型和含义
泛型的参数类型 | 含义 |
---|---|
E-Element | 应用在集合中,作为元素的类型占位符 |
T - Type | Java类参数的类型占位符 |
K - Key & V - Value | M ap键值类型占位符 |
? | 表示不确定的java类型(无限制通配符类型) |
Object | 参数类型是所有类的根类 |
<? extends T> | 限定通配符,类型必须为T类型或者T子类 |
<? super T> | 限定通配符,类型必须为T类型或者T的父类 |
泛型擦除
Java编译器会将多种泛型类形实例映射到唯一的字节码表示,即类型擦除(type erasue)。
实例
List 和 List 等类型在编译之后都会变成 List(泛型擦除)。JVM拿到的类实例对象是同一个 List对象。
List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list1.getClass() == list2.getClass());// true
复制代码
可以通过反射绕过编译前的泛型类型检查
List<Integer> list = new ArrayList<>();
list.add(123);
try {
// 由于List中的泛型参数没有设置上界,所以add方法可以add任何Object的子类型参数
Method method = list.getClass().getDeclaredMethod("add", Object.class);
method.invoke(list, "string");
method.invoke(list, true);
method.invoke(list, 12.3);
list.forEach(e -> System.out.println("e = " + e));
} catch (Exception e) {
e.printStackTrace();
}
--------------------------------------------------------
true
e = 123
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at java.util.ArrayList.forEach(ArrayList.java:1257)
at reflection.Main.main(Main.java:29)
复制代码
当泛型遇到重载
编译报错,因为泛型擦除后,两个方法的参数签名一样。