利用Spring工具类查找泛型

众所周知Spring框架是一个集各种功能于一体的大成架构。
随着时间和版本的推移Spring的功能越来越强大,而且Spring随着Java的版本迭代不断更新升级。
其中Spring为我们提供了非常多的工具。只要你使用了Spring,就可以直接在项目里面进行使用。
不需要重复造轮子。

本文讲解如果通过Spring的工具类进行解析泛型相关操作。

org.springframework.core.ResolvableType 核心工具类

分别通过下列介绍功能

  • 方法相关
  • 属性相关
  • 类相关

前置知识

本文需要你对泛型有基本的概念。还需要一些泛型固化,泛型擦除的相关知识。 会在本段补充

泛型擦除: 众所周知Java是静态语言,最终执行的程序都是由文件编译成的.class(字节码文件)。
当我们new 一个带泛型的内容时(用List举例) 。此时对于向List#add 的参数是只有编译期检查的。
所以以下代码仍然可以通过编译 并且成功运行

 public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        stringList.add("a");
        stringList.add("b");
        List newList = stringList;
        newList.add(1);
        System.out.println(newList);
    }
    // 输出结果:[a, b, 1]

在Java5有了泛型之后,字节码文件中就加入了泛型相关的内容,所以在1.5之后的字节码和1.5之前是有一些不兼容的 ,1.8出了lambda表达式之后 1.8也会有一些不兼容 同理。 因为字节码有有泛型相关信息,所以我们可以通过一些反射操作获取对应的泛型内容。Spring封装了这个繁琐过程,这就是获取泛型信息的原理。

泛型固化: 因为java是静态语言,所以很多动态内容在字节码层面是不能感知的。

用一个方法举例

public List<String> returnStringList(){
	return new ArrayList<>();
}
// 上例确定了方法返回值是泛型为String,所以泛型是固定的

  public <E> List<E> returnEList(E element){
        List<E> result = new ArrayList<>();
        result.add(element);
        return result;
    }
  public  List<?> returnEList(Object element){
        List<Object> result = new ArrayList<>();
        result.add(element);
        return result;
    }
// 上例属于没有固化泛型,所以字节码不会携带这个方法中的返回值泛型内容.  无法获取

// 如果把E变成Object 效果是相同的 但是这时候Object信息就会被带到字节码文件中,就可以获取
  public  List<Object> returnEList(Object element){
        List<Object> result = new ArrayList<>();
        result.add(element);
        return result;
    }

综上所述,只有在方法泛型固化之后才能拿到


有了前置知识,直接开始使用API

ResolvableType类是Spring对Java的信息进行的高阶封装,也可以理解为是一个增强的Class内容

  1. 获取ResolvableType对象
  2. 使用ResolvableType对象的相关Api获取想要的内容

ResolvableType的构造方法是private的,我们不可以直接new出来
ResolvableType自己本身就是一个静态工厂,可以通过静态方法获得不同功能的ResolvableType对象

我列出一些常用的,完整api可以直接点链接查看

你可以直接点进来看原生Api

  • forClass(Class<?> clazz)
  • forField(Field field)
  • forType(Type type)
  • forMethodParameter(Method method, int parameterIndex)
  • forMethodReturnType(Method method)

总结来说就是四种构造

  • 拿到方法参数
  • 拿到方法返回值
  • 拿到属性信息
  • 拿到类信息

最终的对象都是ResolvableType对象,可以通过对象拿到想获得内容

方法返回值

public class ResolverTypeDemo {


    public static void main(String[] args) throws Exception{
        Method resultStringList = ResolverTypeDemo.class.getMethod("resultStringList");
        ResolvableType resolvableType = ResolvableType.forMethodReturnType(resultStringList);
        ResolvableType[] generics = resolvableType.getGenerics();
        Class<?> rawClass = resolvableType.getRawClass();
        System.out.printf("返回值是类型是%s,有%s个泛型,分别是:\n",rawClass.getName(),generics.length);
        Stream.of(generics).map(ResolvableType::getType).forEach(System.out::println);
    }


    public List<String> resultStringList(){
        return null;
    }

}

方法参数

public class ResolverTypeDemo {


    public static void main(String[] args) throws Exception{
        Method resultStringList = ResolverTypeDemo.class.getMethod("resultStringMap");
        ResolvableType resolvableType = ResolvableType.forMethodReturnType(resultStringList);
        ResolvableType[] generics = resolvableType.getGenerics();
        Class<?> rawClass = resolvableType.getRawClass();
        System.out.printf("返回值是类型是%s,有%s个泛型,分别是:\n",rawClass.getName(),generics.length);
        Stream.of(generics).map(ResolvableType::getType).forEach(System.out::println);
    }


    public List<String> resultStringMap(){
        return null;
    }

}

在这里插入图片描述

方法参数

public class ResolverTypeDemo {


    public static void main(String[] args) throws Exception {
        Method resultStringList = ResolverTypeDemo.class.getMethod("paramIntegerList", Map.class);
        ResolvableType resolvableType = ResolvableType.forMethodParameter(resultStringList, 0);
        ResolvableType[] generics = resolvableType.getGenerics();
        Class<?> rawClass = resolvableType.getRawClass();
        System.out.printf("方法第一个参数是%s,有%s个泛型,分别是:\n", rawClass.getName(), generics.length);
        Stream.of(generics).map(ResolvableType::getType).forEach(System.out::println);
    }


    public void paramIntegerList(Map<String,Integer> arg) {

    }

}

在这里插入图片描述

  public static void main(String[] args) throws Exception {
        ResolvableType resolvableType = ResolvableType.forType(StringList.class);

        ResolvableType[] generics = resolvableType.getGenerics();
        for (ResolvableType generic : generics) {
            System.out.println(generic);
        }
        // 此时没有泛型  因为泛型在父类上
        ResolvableType superType = resolvableType.getSuperType();
        ResolvableType[] superTypeGenerics = superType.getGenerics();
        for (ResolvableType superTypeGeneric : superTypeGenerics) {
            System.out.println(superTypeGeneric);
            // 这一行输出java.lang.String
        }
    }

    static class StringList extends ArrayList<String>{

    }

属性

这次用一个复杂属性,嵌套起来

public class ResolverTypeDemo {


    Map<String,List<Integer>> map;

    public static void main(String[] args) throws Exception {
        Field field = ResolverTypeDemo.class.getDeclaredField("map");
        ResolvableType resolvableType  = ResolvableType.forField(field);
        ResolvableType[] generics = resolvableType.getGenerics();
        ResolvableType string = generics[0];
        // 上行应该已经是一个String泛型描述了
        ResolvableType list = generics[1];
        // 上行还是一个list,这个list仍然是ResolvableType 可以继续解析
        ResolvableType[] listGenerics = list.getGenerics();
        ResolvableType listGeneric = listGenerics[0];
        // 此时这个listGeneric 就是Integer 本体了

        System.out.println(string);

        System.out.println(listGeneric);

    }


}

多说一句: 理论上泛型是可以无限嵌套的。 我们可以在约定的情况下用这种泛型工具类解析所有想要得到的内容。 前提是泛型固化

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值