跟着小马哥学系列之 Spring IoC(进阶篇:泛型处理)
学成路更宽,吊打面试官。 ——小马哥
简介
大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间《小马哥讲Spring核心编程思想》基础上形成的个人一些总结。希望能帮助各位小伙伴, 祝小伙伴早日学有所成。 分为基础篇、进阶篇、源码篇。玩游戏看颜色,学技术看版本,本系列以 Spring 5.2.0.RELEASE 版本为基础进行介绍。 祝小伙伴早日学有所成。
泛型基础
-
泛型类型:是在类型上参数化的泛型类或接口
-
泛型使用场景
- 编译时强类型检查
- 避免类型转换
- 实现通用算法
-
泛型类型擦写
- 泛型被引用到 Java 语言中以便在编译时提供更加严格的类型检查并支持泛型编程。类型擦写确保不会为参数化类型创建新类型;泛型不会产生运行时开销。为了实现泛型,编译器将类型擦写应用于:
- 将泛型类型中的所有类型参数替换为其边界,如果类型参数是无边界的,则将其替换为 Object。因此生成的字节码只包含普通类、接口和方法
- 必要时插入类型转换以保证类型安全
- 生成桥接方法以保留扩展泛型类型中的多态性
- 泛型被引用到 Java 语言中以便在编译时提供更加严格的类型检查并支持泛型编程。类型擦写确保不会为参数化类型创建新类型;泛型不会产生运行时开销。为了实现泛型,编译器将类型擦写应用于:
Java 5 类型接口
-
Java 5 类型接口:java.lang.reflect.Type
Type 是 Java 编程语言中所有类型的公共超接口。这些类型包括原始类型(raw type)、参数化类型(parameterized type)、数组类型(array type)、类型变量(type variable )和原生类型(primitive type)。
派生类或接口 说明 java.lang.Class Java 类 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 的局限性
- ResolvableType 无法处理泛型擦写
- ResolvableType 无法处理非具体化的 ParameterizedType