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

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];

联系我们

联系电话

4000-640-466

联系邮箱

service@f-li.cn

办公地址

上海黄浦区外滩源1号

谢谢,您的信息已成功发送。
请填写信息。