一.Type类是啥
Type是Java 编程语言中所有类型的公共高级接口(官方解释),也就是Java中所有类型的"爹",它并不是我们平常工作中经常使用的 int、String、List、Map等数据类型,而是从Java语言角度来说,对基本类型、引用类型向上的抽象;
Type体系中类型的包括:
- 原始类型(Type):不仅仅包含我们平常所指的类,还包括枚举、数组、注解等
- 参数化类型(ParameterizedType):就是我们平常所用到的泛型List<String>、Map<K,V>,Set<T>,Class<?>
- 数组类型(GenericArrayType):并不是我们工作中所使用的数组String[] 、byte[],而是带有泛型的数组,即T[]
- 类型变量(TypeVariable):比如 T a
- 基本类型(Class):原始类型,每个类(貌似接口也有)都会有个Class对象
我们重点看一下ParameterizedType :
java
public interface ParameterizedType extends Type {
// 获取<>中实际的类型参数,以Type数组形式返回
Type[] getActualTypeArguments();
// 获取<>前面的类型
Type getRawType();
// 如果这个类型是某个类型所属,则获取这个所有者的类型,否则返回null,比如Map.Entry<Sting,String>,会返回Map
Type getOwnerType();
}
具体可参考:https://www.jianshu.com/p/0f3eda48d611
二.如何获得泛型T的真实类型
反射拿到泛型接口的实现类的实际泛型类型
定义一个泛型接口和他的实现类:
java
public interface IMessageSender<T,K> {
K sendMsg(T msg);
}
public class SmsMessageImpl implements IMessageSender<String, List<Integer>>, Serializable{
@Override
public List<Integer> sendMsg(String msg) {
return new ArrayList<>();
}
}
通过反射拿到SmsMessageImpl实现的接口里面的T,K的真实类型:
java
/**
* 反射拿到泛型接口的实现类的实际泛型类型
*/
public static void testClassGenericActualType1(){
System.out.println("testClassGenericActualType1开始");
//getGenericInterfaces返回表示由此对象表示的类或接口直接实现的接口的Type
//IMessageSender<String, List<Integer>>
Type genericInterfaces1 = SmsMessageImpl.class.getGenericInterfaces()[0];
//Serializable
Type genericInterfaces2 = SmsMessageImpl.class.getGenericInterfaces()[1];
//输出的是sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
System.out.println(genericInterfaces1.getClass());
//输出的是class java.lang.Class
System.out.println(genericInterfaces2.getClass());
//返回表示此类型实际类型参数的 Type对象的数组
Type[] actualTypeArguments = ((ParameterizedType)genericInterfaces1).getActualTypeArguments();
//class java.lang.String , java.util.List<java.lang.Integer>
//这边直接拿到了SmsMessageImpl中两个实际泛型类型
System.out.println("反射拿到泛型接口的实现类的实际泛型类型:"+actualTypeArguments[0] + " , "+ actualTypeArguments[1]);
System.out.println("testClassGenericActualType1结束");
}
输出结果是:
java
testClassGenericActualType1开始
class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
class java.lang.Class
反射拿到泛型接口的实现类的实际泛型类型:class java.lang.String , java.util.List<java.lang.Integer>
testClassGenericActualType1结束
反射拿到父类的实际泛型类型
定义一个泛型类,和他的子类:
java
public class MessageSender <T>{
}
public class SmsMessage extends MessageSender<String>{
}
通过对SmsMessage的class对象进行反射拿到父类里面真实的String类型:
java
public static void testClassGenericActualType2(){
System.out.println("testClassGenericActualType2开始");
//返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的Type。如果超类是
//参数化类型,则返回的 Type 对象必须准确反映源代码中所使用的实际类型参数
Type genericSuperclass = SmsMessage.class.getGenericSuperclass();
Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass).getActualTypeArguments();
System.out.println("反射拿到父类的实际泛型类型:"+actualTypeArguments[0]);
System.out.println("testClassGenericActualType2结束");
}
输出结果是:
java
testClassGenericActualType2开始
反射拿到父类的实际泛型类型:class java.lang.String
testClassGenericActualType2结束
反射获取方法参数上泛型参数的实际类型
我们定义了一个verify方法:
java
public class Main {
public static void main(String[] args) throws NoSuchMethodException{
testMethodGenericActualType();
}
/**
* 获取方法参数上泛型参数的实际类型
* @throws NoSuchMethodException
*/
public static void testMethodGenericActualType() throws NoSuchMethodException {
System.out.println("testMethodGenericActualType开始");
//反射拿到Main.class中的verify方法
Method method = Main.class.getMethod("verify", Map.class);
//反射拿到verify方法的参数列表的第一个参数
Parameter parameter = method.getParameters()[0];
Type type = parameter.getParameterizedType();
//由于参数是带泛型的,因此type的实际类型是ParameterizedType,
//可以强制转换为ParameterizedType,然后获取参数Map中的两个泛型参数: <String,Integer>
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
System.out.println("获取方法参数上泛型参数的实际类型:"+actualTypeArguments[0] + " , " + actualTypeArguments[1]);
System.out.println("testMethodGenericActualType结束");
}
/**
* 用于测试获取方法参数上泛型参数的实际类型
* @param map
*/
public void verify(Map<String,Integer> map){
}
}
输出结果是:
java
testMethodGenericActualType开始
获取方法参数上泛型参数的实际类型:class java.lang.String , class java.lang.Integer
testMethodGenericActualType结束
反射获取字段上泛型参数的实际类型
java
public class Main {
public static void main(String[] args) throws NoSuchFieldException {
testFieldGenericActualType();
}
/**
* 获取字段上泛型参数的实际类型
*/
public static void testFieldGenericActualType() throws NoSuchFieldException {
System.out.println("testFieldGenericActualType开始");
Field field = Main.class.getDeclaredField("list");
//获取字段泛型
ParameterizedType genericType = (ParameterizedType) field.getGenericType();
Type[] actualTypeArguments = genericType.getActualTypeArguments();
//得到字段List<String>泛型中的实际类型String
System.out.println("获取字段上泛型参数的实际类型:"+actualTypeArguments[0]);
System.out.println("testFieldGenericActualType结束");
}
private List<String> list;
}
输出结果是:
java
testFieldGenericActualType开始
获取字段上泛型参数的实际类型:class java.lang.String
testFieldGenericActualType结束