跟着小马哥学系列之 Spring IoC(进阶篇:泛型处理)

学成路更宽,吊打面试官。 ——小马哥

简介

大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间《小马哥讲Spring核心编程思想》基础上形成的个人一些总结。希望能帮助各位小伙伴, 祝小伙伴早日学有所成。 分为基础篇、进阶篇、源码篇。玩游戏看颜色,学技术看版本,本系列以 Spring 5.2.0.RELEASE 版本为基础进行介绍。 祝小伙伴早日学有所成。

泛型基础

  • 泛型类型:是在类型上参数化的泛型类或接口

  • 泛型使用场景

    • 编译时强类型检查
    • 避免类型转换
    • 实现通用算法
  • 泛型类型擦写

    • 泛型被引用到 Java 语言中以便在编译时提供更加严格的类型检查并支持泛型编程。类型擦写确保不会为参数化类型创建新类型;泛型不会产生运行时开销。为了实现泛型,编译器将类型擦写应用于:
      • 将泛型类型中的所有类型参数替换为其边界,如果类型参数是无边界的,则将其替换为 Object。因此生成的字节码只包含普通类、接口和方法
      • 必要时插入类型转换以保证类型安全
      • 生成桥接方法以保留扩展泛型类型中的多态性

Java 5 类型接口

  • Java 5 类型接口:java.lang.reflect.Type

    Type 是 Java 编程语言中所有类型的公共超接口。这些类型包括原始类型(raw type)、参数化类型(parameterized type)、数组类型(array type)、类型变量(type variable )和原生类型(primitive type)。

    派生类或接口说明
    java.lang.ClassJava 类 API,如 java.lang.String
    java.lang.reflect.GenericArrayType泛型数组类型
    java.lang.reflect.ParameterizedType泛型参数类型
    java.lang.reflect.TypeVariable泛型类型变量,如 Collection<E> 中的 E
    java.lang.reflect.WildcardType泛型通配类型
  • Java 泛型反射 API

    类型API
    泛型信息(Generics Info)java.lang.Class#getGenericInfo()
    泛型参数(Parameters)java.lang.reflect.ParameterizedType
    泛型父类(Super classes)java.lang.Class#getGenericSuperclass()
    泛型接口(Interfaces)java.lang.Class#getGenericInterfaces()
    泛型声明(Generic Declaration)java.lang.reflect.GenericDeclaration

Spring 泛型辅助类

类型辅助类

  • 核心 API:org.springframework.core.GenericTypeResolver

    用于根据类型变量(type variables)解析泛型类型的辅助类。主要用于框架内使用,解析方法参数类型,即使它们是泛型声明的。

    • 版本支持:2.5.2+
    • 处理类型有相关方法
      • resolveRetureType
      • resolveType
    • 处理泛型参数类型相关方法
      • resolveReturnTypeArgumen
      • resolveTypeArgument
      • resolveTypeArguments
    • 处理泛型类型变量相关方法
      • getTypeVariableMap
public class GenericTypeResolverDemo {
    public static void main(String[] args) throws NoSuchMethodException {
        Method getStringMethod = GenericTypeResolverDemo.class.getDeclaredMethod("getString");
        Method genericReturnMethod = GenericTypeResolverDemo.class.getDeclaredMethod("genericReturn");
        Class<?> getStringMethodReturnType = GenericTypeResolver.resolveReturnType(getStringMethod, GenericTypeResolverDemo.class);
        Class<?> getStringMethodReturnTypeArgument = GenericTypeResolver.resolveReturnTypeArgument(getStringMethod, GenericTypeResolverDemo.class);
        Class<?> genericReturnMethodReturnTypeArgument = GenericTypeResolver.resolveReturnTypeArgument(genericReturnMethod, List.class);
        Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(Properties.class);
        // getString 方法返回值类名:java.lang.String
        System.out.printf("getString 方法返回值类名:%s\n", getStringMethodReturnType.getName());
        // getString 方法返回值泛型为:null
        System.out.printf("getString 方法返回值泛型为:%s\n", getStringMethodReturnTypeArgument);
        // genericReturn 方法返回值泛型为:class java.lang.String
        System.out.printf("genericReturn 方法返回值泛型为:%s\n", genericReturnMethodReturnTypeArgument);
        // Properties 类泛型类型变量为:{K=class java.lang.Object, V=class java.lang.Object, V=class java.lang.Object, K=class java.lang.Object, V=class java.lang.Object, K=class java.lang.Object}
        System.out.printf("Properties 类泛型类型变量为:%s\n", typeVariableMap);

    }

    public static String getString() {
        return null;
    }

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


集合类型辅助类

  • 核心 API:org.springframework.core.GenericCollectionTypeResolver
    • 版本支持:2.0 - 4.3
    • 替换实现:org.springframework.core.ResolvableType
    • 处理 Collection 相关:getCollection*Type
    • 处理 Map 相关:getMapKey*Type/getMapValue*Type

Spring 方法参数封装:MethodParameter

封装方法参数说明的Helper类,即方法或构造函数加上参数索引和已声明泛型类型的嵌套类型索引。作为要传递的规范对象很有用。从 4.2 开始,有一个 SynizingMethodParameter 子类可用来合成带有属性别名的注解。这个子类特别用于 web 和消息端点处理。

  • 核心 API:org.springframework.core.MethodParameter
    • 版本支持:2.0+
    • 元信息
      • 关联的方法:Method
      • 关联的构造器:Constructor
      • 构造器或方法参数索引:parameterIndex
      • 构造器或方法参数类型:parameterType
      • 构造器或方法泛型类型:genericParameterType
      • 构造器或方法参数名称:parameterName
      • 所在的类:containingClass
public class MethodParameterDemo {
    public static void main(String[] args) throws NoSuchMethodException {
        // parameterIndex -1 表示方法返回参数类型
        MethodParameter methodReturnParameter = new MethodParameter(MethodParameterDemo.class.getDeclaredMethod("doSomething", String.class), -1);
        // parameterIndex 0 表示第1个方法参数
        MethodParameter methodParameter = new MethodParameter(MethodParameterDemo.class.getDeclaredMethod("doSomething", String.class), 0);
        System.out.println(methodReturnParameter.getGenericParameterType().getTypeName());
        System.out.println(methodParameter.getParameter().getType());
    }


    public List<String> doSomething(String name) {
        return new ArrayList<>();
    }
}

Spring 4.2 泛型优化实现:ResolvableType

封装Java类型,提供对超类型(getSuperType())、接口(getInterfaces())和泛型参数(getGeneric(int…))的访问,以及最终解析(resolve())为 Class 的能力。ResolvableType 可以从字段(forField(Field))、方法参数(forMethodParameter(Method, int))、方法返回(forMethodReturnType(Method))或类中获得(forClass(Class))。这个类上的大多数方法本身将返回 ResolvableType 。

  • 核心 API: org.springframework.core.ResolvableType
    • 版本支持:4.0+
    • 扮演角色:GenericTypeResolver 和 GenericCollectionTypeResolver 替代者
    • 工厂方法:for* 方法
    • 转换方法:as* 方法
    • 处理方法:resolve* 方法
public class ResolvableTypeDemo implements Converter<String, Object> {
	private HashMap<Integer, List<String>> myMap;
	public void example() {
	    ResolvableType t = ResolvableType.forField(getClass().getDeclaredField("myMap"));
	    t.getSuperType(); // AbstractMap<Integer, List<String>>
	    t.asMap(); // Map<Integer, List<String>>
	    t.getGeneric(0).resolve(); // Integer
	    t.getGeneric(1).resolve(); // List
	    t.getGeneric(1); // List<String>
	    t.resolveGeneric(1, 0); // String
	}
    public static void main(String[] args) {
        ResolvableType resolvableType = ResolvableType.forClass(ResolvableTypeDemo.class).as(Converter.class);
        ResolvableType[] generics = resolvableType.getGenerics();
        if (generics.length < 2) {
            return;
        }
        Class<?> sourceType = generics[0].resolve();
        Class<?> targetType = generics[1].resolve();
        System.out.printf("Converter 接口 sourceType %s\n", sourceType.getName());
        System.out.printf("Converter 接口 targetType %s\n", targetType.getName());

    }

    @Override
    public Object convert(@Nullable String source) {
        return null;
    }
}

ResolveableType 的局限性

  1. ResolvableType 无法处理泛型擦写
  2. ResolvableType 无法处理非具体化的 ParameterizedType
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿大叔文海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值