Java泛型K V E T ?以及 泛型擦除的理解

泛型的使用不多说了。详细谈谈常见通配符的区别:

  • K V代表键值对
  • E 代表Element
  • T 某个具体的Java类型,在使用时需要被指定。

实际上具体是用KVET哪个字母,都一样,只是他们代表的东西是约定成成俗的,我用ABCDE可不可以呢,当然可以!

  • ? 代表不确定 的Java类型。通配符,多用在函数的参数声明,不加限定就时是Object及其子类。

限定extends 和 super

  • <? extends E>

    必须是E的子类或者E本身,如果不是,编译失败

  • <? super E>

    必须是E或者E的父类,直到Object。E的子类不可以。

List<?> list; // 通配符,任何类都可以,实际没啥意义。
List<? extends Animal> list; // Animal和他的子类都可以
List<Animal> list; // 这个存入的时候只能是Animal,不可以是子类。

然而,T只有,E及其子类都可以。不能使用~~~~。因为T要在声明类的时候指定,这就和super本身的意思矛盾了。

?和T的区别

其实最本质的区别就是,无论在什么地方,在声明一个类或者借口的时候,T就变成了一个已知的类型。?是Object及其子类或者是用extends限定的,并不能在声明的时候去定义它。

  • T是确定的,通常是泛型类、泛型方法的定义。

  • ?通配符,多用来在作为泛型方法的形参,用来声明变量没啥意义,因为他本身代表Object。

// 能保证是一个类型,因为在使用这个函数之前,T就是一个确定的东西,该函数中所有的T都是这个类型。
public <T extends Number> void test(List<T> dest, List<T> src) 
    
//通配符是 不确定的,所以这个方法不能保证两个 List 具有相同的元素类型
public void test(List<? extends Number> dest, List<? extends Number> src);
  • T 可以多重限定,?不行。

    <T extends A & B> // 可以这么写,T是一个确定的类型,必须是A和B的公共子类或同时实现了这两个接口。
    <? extends A & B> // 不可以。通配符不能多重限定。
    

泛型擦除

Java是伪泛型,即都是在编译的时候,所有的泛型信息都被擦除了,编译后的字节码不包括任何的泛型信息。这就导致在通过反射调用类型ArrayList的add方法,可以添加非Integer元素而不报错。

List<Integer> list = new ArrayList<>();
list.getClass().getMethod("add", Object.class).invoke(list, "abc");

因为编译之后擦出了Integer这个类型。如果没有使用extends限定,就是Object,否则就换成限定类型。
并且,会在结果字节码中插入强制类型转换,来将原始类型转换为泛型。
具体见参考2

参考

  1. 聊一聊-JAVA 泛型中的通配符 T,E,K,V,?

  2. Java泛型类型擦除以及类型擦除带来的问题

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页