reflect.Type 接口学习笔记

最近在看Mybaits源码,看到参数解析的时候有这样一段代码:

private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) {
    Class<?> rawType = (Class<?>) parameterizedType.getRawType();
    Type[] typeArgs = parameterizedType.getActualTypeArguments();
    Type[] args = new Type[typeArgs.length];
    for (int i = 0; i < typeArgs.length; i++) {
      if (typeArgs[i] instanceof TypeVariable) {
        args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
      } else if (typeArgs[i] instanceof ParameterizedType) {
        args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
      } else if (typeArgs[i] instanceof WildcardType) {
        args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
      } else {
        args[i] = typeArgs[i];
      }
    }
    return new ParameterizedTypeImpl(rawType, null, args);
  }

涉及到java reflect包的Type体系,对这一体系做一个学习笔记:

Type是一个接口但没有任何方法(java1.8中增加了一个方法getTypeName()),其下有四个子接口:ParameterizedType,GenericArrayType,TypeVariable和WildcardType,分别对应参数化类型,泛型数组,类型变量和通配符,还有一个熟悉的Class类,其实也是这个接口的实现类,可以理解为代表普通和基本类型。


一、ParameterizedType为参数化的类型,例如List<String>,Map<String, Integer>等,有3个方法,分别是getActualTypeArguments()、 getRawType()、 getOwnerType():

1、getActualTypeArguments()获取泛型中的实际类型,可能会存在多个泛型,例如Map<K,V>,所以会返回Type[]数组;

2、getRawType()获取泛型的声明类型或接口,对Map<K,V> 来说是Map(的Class类),对HashMap来说是HashMap(的Class类)。

3、getOwnerType()可以从源码注释中得知是获取“拥有者”,即内部类的外层类,例如Map.entry<K,V>的OwnerType就是Map,若该类是一个顶层的类,则返回null。
 

public class TestMain {

  private Map<String, Integer> map = new HashMap<>();

  public static void main(String[] args) throws NoSuchFieldException {
    Field field = TestMain.class.getDeclaredField("map");
    Type genericType = field.getGenericType();
    ParameterizedType parameterizedType = (ParameterizedType) genericType;
    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();


    Type actualTypeArgument = actualTypeArguments[0]; 
    System.out.println(actualTypeArgument);   //java.lang.String
    System.out.println(actualTypeArguments[1]);   //java.lang.Integer

    Type ownerType = parameterizedType.getOwnerType();
    System.out.println(ownerType);  // null

    Type rawType = parameterizedType.getRawType();
    System.out.println(rawType);   // interface  java.util.Map

    System.out.println(genericType);

  }
}

二、GenericArrayType为泛型数组,例如List<String>[] 、T[]等;注意Integer[],int[] 等不属于GenericArrayType,而属于普通类型(Class,isArray()方法返回true),由于Java中不允许(直接)实例化泛型数组(原因可参看《Effective Java II》 第25条),而只能通过反射等其他绕过编译器检测的方法创建泛型数组实例,并且《Effective Java II》中说明集合优于数组,泛型数组也可以用集合取代,所以实际中遇到的泛型数组较少,该类型也使用较少。

GenericArrayType接口中,仅有1个方法:getGenericComponentType(),返回泛型数组中元素的Type类型,即List<String>[] 中的 List<String>(ParameterizedTypeImpl)、T[] 中的T(TypeVariableImpl)。

public class TestMain {
  private List<String>[] listString;
  private List<?>[] listArray;

  public static void main(String[] args) throws NoSuchFieldException {
    Field listArray = TestMain.class.getDeclaredField("listString");
    Type genericType = listArray.getGenericType();
    GenericArrayType genericArrayType = (GenericArrayType) genericType;
    Type genericComponentType = genericArrayType.getGenericComponentType();
    System.out.println(genericComponentType);   // java.util.List<java.lang.String>

    Field field = TestMain.class.getDeclaredField("listArray");
    Type genericType1 = field.getGenericType();
    GenericArrayType genericArrayType1 = (GenericArrayType) genericType1;
    Type genericComponentType1 = genericArrayType1.getGenericComponentType();
    System.out.println(genericComponentType1); // java.util.List<?>

  }
}

三、TypeVariable和WildcardType都是描述<>里面内容的接口,TypeVariable为类型参数(<>中没有?,如<S,T>),在TypeVariable接口中,有4个方法,分别为getBounds()、getGenericDeclaration()、getName()和getAnnotatedBounds()(java1.8新增):

getBounds():获得该类型变量的上限,也就是泛型中extend右边的值;例如 List<T extends Number> ,Number就是类型变量T的上限;如果我们只是简单的声明了List<T>(无显式定义extends),那么默认为Object(注意如果泛型描述为T而不是?通配符的话是不能规定下边界的,即不可以使用super关键字);

getGenericDeclaration():获取声明该类型变量实体,也就是TastMain<T>中的TastMain;

getName():获取类型变量在源码中定义的名称,也就是TastMain<T>中的TastMain;

getAnnotatedBounds(): //todo

public class TestMain<T> {

  private T t;

  public static void main(String[] args) throws NoSuchFieldException {
    Field field = TestMain.class.getDeclaredField("t");
    Type genericType = field.getGenericType();
    TypeVariable typeVariable = (TypeVariable) genericType;
    Type[] bounds = typeVariable.getBounds();
    GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
    String name = typeVariable.getName();
    AnnotatedType[] annotatedBounds = typeVariable.getAnnotatedBounds();
    System.out.println(bounds);   //[Ljava.lang.reflect.Type;@2aae9190
    System.out.println(genericDeclaration);  // class test.TestMain
    System.out.println(name);  // T
    System.out.println(annotatedBounds);  //[Ljava.lang.reflect.AnnotatedType;@2f333739
  }
}

四、WildcardType为通配符参数(<>中有?,如<? extend Number>),WildcardType接口,有2个方法,分别为getUpperBounds()、getLowerBounds():分别是获取泛型描述的通配符的上边界和下边界(比较简单,不再举例)。

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值