java怎样动态获取泛型参数的类型

 更新时间:2024年09月19日 10:30:55   作者:Android海纳百川  
在Java中,泛型信息在编译时会被擦除,但可以通过特定API获取运行时的泛型参数类型,主要API包括Class的getGenericSuperclass()和getGenericInterfaces()方法,以及ParameterizedType的getActualTypeArguments()方法

Java如何动态获取泛型参数的类型

我们都知道java中的泛型其实是伪泛型,java在编译阶段会对变异类型进行擦除,擦出到泛型类的最小上限,编译后得到的class文件里面是没有任何泛型信息的,泛型的控制其实就是java编译器进行的控制,编译阶段进行泛型检查。

那如果我们想在运行时知道泛型类的类型,如何做到呢?

主要用到下面几个api:

1、public Type getGenericSuperclass()---Class类的方法

2、Type[] getActualTypeArguments()---ParameterizedType方法

3、public Type[] getGenericInterfaces()---Class类的方法

  • 我们先定义一个泛型类:
public class Father<T> {
}
  • 再定义一个子类:
public class Son extends Father<String>{
}
  • 先来看看下面代码:
System.out.println(Son.class.getGenericSuperclass());
System.out.println(Son.class.getSuperclass());
System.out.println(Father.class.getGenericSuperclass());
System.out.println(Father.class.getSuperclass());

运行结果如下:

从上面运行结果可以看出两点:

(1)通过Class类的getGenericSuperclass()是可以获取到泛型信息的;

(2)泛型类本身是无法获取到泛型信息的,只能通过泛型类的子类来获取泛型信息,这也很好解释,因为泛型类比如Father类自身,其泛型参数并未确定,自然无法获取泛型信息,而子类的泛型参数类型已经确定,父类泛型信息已经确定,所以可以查询。

具体的查询泛型参数类型的代码如下:

ParameterizedType parameterizedType = (ParameterizedType) Son.class.getGenericSuperclass();
System.out.println(parameterizedType.getClass().getName());
System.out.println(parameterizedType);
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for(Type actualTypeArgument: actualTypeArguments) {
    System.out.println(actualTypeArgument.getClass().getName());  
	System.out.println(actualTypeArgument); 
} 

运行结果如下:

由上图运行结果可知:

(1)getGenericSuperclass()返回的实际类型为ParameterizedTypeImpl,这里面带有父类的泛型类型信息;

(2)获取泛型参数信息是通过ParameterizedType的getActualTypeArguments方法,该方法返回的是一个Type类型的数据,该数据存放的数据的实际类型为Class,也就是我们得到了泛型参数的类信息。

上面讲述的是获取父类的泛型类型,那接口的泛型类型如何获取呢?

  • 先贴一个简单的接口:
public interface ITest<T> {
}
  • 我们让Son类实现该方法:
public class Son extends Father<String> implements ITest<Integer>{
}
  • 获取ITest的泛型参数类型的方法如下:
ParameterizedType parameterizedType = (ParameterizedType) Son.class.getGenericInterfaces()[0];
System.out.println(parameterizedType.getClass().getName());
System.out.println(parameterizedType);
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for(Type actualTypeArgument: actualTypeArguments) { 
	System.out.println(actualTypeArgument.getClass().getName());
	System.out.println(actualTypeArgument); 
} 

运行结果如下:

和泛型类区别就是getGenericSuperclass()方法换成了getGenericInterfaces(),getGenericInterfaces()方法返回的是Type[],因为一个类可以实现多个接口,所以想要获取哪个接口的泛型信息,需要指定数据下标,这里Son类就实现了一个接口,所以直接Son.class.getGenericInterfaces()[0]就可以了。

上面的代码有一个共同点

就是泛型类或者泛型接口已经有一个子类了,通过子类的Class信息可以获取到泛型父类或者泛型接口的泛型类型信息,那么如果没有子类,怎么直接获取泛型类的泛型类型信息呢?

很简单,通过匿名内部类(其实还是通过子类).

new Father<Integer>() {}.getClass().getGenericSuperclass();
new ITest<Integer>() {}.getClass().getGenericInterfaces())[0];

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot+MinIO实现对象存储的示例详解

    SpringBoot+MinIO实现对象存储的示例详解

    MinIO 是一个基于Apache License v2.0开源协议的对象存储服务,它是一个非常轻量的服务,可以很简单的和其他应用的结合,所以下面我们就来看看SpringBoot如何整合MinIO实现对象存储吧
    2023-10-10
  • java如何读取文件目录返回树形结构

    java如何读取文件目录返回树形结构

    这篇文章主要介绍了java如何读取文件目录返回树形结构问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • 基于SpringBoot实现用户身份验证工具

    基于SpringBoot实现用户身份验证工具

    这篇文章主要介绍了基于SpringBoot实现的用户身份验证工具,非常不错,具有参考借鉴价值 ,需要的朋友可以参考下
    2018-04-04
  • java中list使用时需避免的场景总结

    java中list使用时需避免的场景总结

    众所周知,Java为开发者提供了多种集合类的实现,其中几乎所有业务代码都需要用到List,但List的错误使用也会导致诸多问题,所以本文我们就来看一看几个错误使用List的场景吧
    2023-10-10
  • Java生成非对称型加密公钥和私钥的方法

    Java生成非对称型加密公钥和私钥的方法

    这篇文章主要介绍了Java生成非对称型加密公钥和私钥的方法,涉及java非对称加密的原理与实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • SpringBoot整合ELK使用教程

    SpringBoot整合ELK使用教程

    对于一个运行中的应用来说,线上排查问题是一件很头疼的问题,不管是springboot单应用,还是springcloud微服务应用,一旦在生产环境出了问题,大多数人第一反应就是赶紧去看日志查问题,本文给大家介绍了SpringBoot整合ELK使用教程,需要的朋友可以参考下
    2024-11-11
  • java教程散列表和树所对应容器类及HashMap解决冲突学习

    java教程散列表和树所对应容器类及HashMap解决冲突学习

    本篇篇文章是java教程,主要介绍了java教程散列表,树所对应容器类及HashMap解决冲突的学习,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2021-10-10
  • java文件操作之java写文件简单示例

    java文件操作之java写文件简单示例

    这篇文章主要介绍了java文件操作中的java写文件示例,需要的朋友可以参考下
    2014-03-03
  • 剑指Offer之Java算法习题精讲数组查找与字符串交集

    剑指Offer之Java算法习题精讲数组查找与字符串交集

    跟着思路走,之后从简单题入手,反复去看,做过之后可能会忘记,之后再做一次,记不住就反复做,反复寻求思路和规律,慢慢积累就会发现质的变化
    2022-03-03
  • Spring实战之类级别缓存实现与使用方法

    Spring实战之类级别缓存实现与使用方法

    这篇文章主要介绍了Spring实战之类级别缓存实现与使用方法,结合实例形式分析了Spring类级别缓存配置、属性、领域模型等相关操作技巧,需要的朋友可以参考下
    2020-01-01

最新评论