【Java基础】了解泛型

「这是我参与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)
复制代码

当泛型遇到重载

编译报错,因为泛型擦除后,两个方法的参数签名一样。

Guess you like

Origin juejin.im/post/7034434170638041102