Java泛型的原始类型

众所周知,Java中的泛型在编译期被擦除,那有没有办法在运行时获取到泛型的原始类型呢?有的。

获取泛型类型

如果定义一个类X,这个类继承自某泛型类,并给泛型提供一个具体的类型,那这个类X就会在类型定义中保留泛型类型。

直接上代码:

Object list = new ArrayList<String>() {
};

Type genericSuper = list.getClass().getGenericSuperclass();
if (genericSuper instanceof ParameterizedType) {
    Type[] types = ((ParameterizedType) genericSuper).getActualTypeArguments();
    for (Type t : types) {
        System.out.println(t);
    }
}
// 输出
>  class java.lang.String

首先这里定义了ArrayList的一个匿名子类,然后通过反射,就可以获取到泛型的具体类型了。

这里的子类化很重要。看一下如果把第一行的子类化去掉会怎样?

Object list = new ArrayList<String>();
// 其他不变
输出:
> E

这个E是ArrayList定义里面的E,如果我们使用HashMap测试,就会出现下面的结果:

Object list = new HashMap<String, String>();
// 其他不变
// 输出
> K
> V

说明 getActualTypeArguments 拿到的是类型定义时,给泛型提供的名称,如果提供的是具体的类型,则为类型的完整名称。

强制转换

运行时通过类型强制转换的成功与否,能否确定泛型类型?答案是不能。

看下面代码。显示创建了一个ArrayList<String>对象,但是把对象赋值给了一个Object类型。此时编译期类型擦除已生效,后续可以对obj对象随意的搓圆压扁(转换为泛型为任何类型的ArrayList类型),没有任何异常。当然如果对里面的内容进行错误的读写,就会遭遇类型转换异常的大棒。

Object obj = new ArrayList<String>();

List<Integer> intList = (List<Integer>) obj; // 成功
List<String> strList = (List<String>) obj; // 成功

如果保留obj的类型会怎样?

List<String> obj = new ArrayList<String>();

List<String> strList = (List<String>) obj;// 成功
List<Integer> intList = (List<Integer>) obj; // 编译失败

很明显,类型在上面摆着,这样的转换在编译期就无法通过,因为这时还没有进行“类型擦除”。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。