Spring泛型处理源码详解,Java泛型处理

文章目录

  • 一、Java 泛型基础
    • 1、泛型类型擦写
      • 代码实例
    • 2、Java 5 类型接口
      • 源码分析
      • 代码实例
    • 3、更多java泛型相关基础
  • 二、Spring旧版本泛型处理
    • 1、Spring 泛型类型辅助类
      • 代码实例
    • 2、Spring 泛型集合类型辅助类
      • 代码实例
    • 3、Spring 方法参数封装
  • 三、Spring 4.0泛型优化实现
    • 1、ResolvableType
      • 源码分析
      • 代码实例
    • 2、ResolvableType 的局限性
    • 3、ResolvableType 的设计优势
  • 参考资料

一、Java 泛型基础

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

泛型使用场景:
• 编译时强类型检查
• 避免类型强转
• 实现通用算法

1、泛型类型擦写

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

代码实例

List<String> list = new ArrayList<>();
list.add("hello");
list.add("world");

// 1.将有泛型约束的list赋值给没有泛型约束的一个新集合
List temp = list;

// 2.此时temp可以添加任意对象到集合中
temp.add(2);

// 3.使用temp获取集合中的元素可以正常获取,没有泛型约束意味着参数类型无边界
// 则将其泛型替换为Object类型
System.out.println(temp.get(2));

// 4.使用list获取集合中的元素会抛出类型转换异常,因为list集合的泛型为String类型
// 在获取元素时,会进行一次类型转换将元素转为String类型,所以会报错
System.out.println(list.get(2));

Java泛型 更多的是编译期间给我们做的强类型约束,而运行时JVM不会关心泛型的类型。

2、Java 5 类型接口

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

派生类或接口 说明
java.lang.Class Java 类 API,如 java.lang.String
java.lang.reflect.GenericArrayType 泛型数组类型
java.lang.reflect.ParameterizedType 泛型参数类型
java.lang.reflect.TypeVariable 泛型类型变量,如 Collection 中的 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()
泛型声明(Generics Declaration) java.lang.reflect.GenericDeclaration

源码分析

我们看一下Class类,实现了Type接口。

public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {

Type接口在JDK1.8之前,是一个空的接口,表示Java编程语言中所有类型的公共超接口。这些类型包括原始类型、参数化类型、数组类型、类型变量和基本类型。1.8之后增加了一个方法:

public interface Type {

    default String getTypeName() {
        return toString();
    }
}

Class中有着很多对泛型操作的方法,获取的泛型类型就是Type类型。

代码实例

// 基本类型 primitive types : int long float
Class intClass = int.class;

// 数组类型 array types : int[],Object[]
Class objectArrayClass = Object[].class;

// 原始类型 raw types : java.lang.String
Class rawClass = String.class;

// 泛型参数类型 parameterized type
ParameterizedType parameterizedType = (ParameterizedType) ArrayList.class.getGenericSuperclass();

//  parameterizedType.getRawType() = java.util.AbstractList

// 泛型类型变量 Type Variable:

System.out.println(parameterizedType.toString()); // java.util.AbstractList

// 
Type[] typeVariables = parameterizedType.getActualTypeArguments();

Stream.of(typeVariables)
        .map(TypeVariable.class::cast) // Type -> TypeVariable
        .forEach(System.out::println);

java反射获取泛型此处只做简单实例。

3、更多java泛型相关基础

更多java泛型相关基础请自行学习,本文主要介绍Spring对泛型的处理。

二、Spring旧版本泛型处理

1、Spring 泛型类型辅助类

核心 API - org.springframework.core.GenericTypeResolver

版本支持:[2.5.2 , )

处理类型相关(Type)相关方法
• resolveReturnType
• resolveType

处理泛型参数类型(ParameterizedType)相关方法
• resolveReturnTypeArgument
• resolveTypeArgument
• resolveTypeArguments

处理泛型类型变量(TypeVariable)相关方法
• getTypeVariableMap

代码实例


import org.springframework.core.GenericTypeResolver;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * {@link GenericTypeResolver} 示例
 */
public class GenericTypeResolverDemo {

    public static void main(String[] args) throws NoSuchMethodException {

        // String 是 Comparable 具体化
        displayReturnTypeGenericInfo(GenericTypeResolverDemo.class, Comparable.class, "getString");

        // ArrayList 是 List 泛型参数类型的具体化
        displayReturnTypeGenericInfo(GenericTypeResolverDemo.class, List.class, "getList");

        // StringList 也是 List 泛型参数类型的具体化
        displayReturnTypeGenericInfo(GenericTypeResolverDemo.class, List.class, "getStringList");

        // 泛型参数类型的具体化 具备 ParameterizedType 返回,否则 null

        // TypeVariable
        Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(StringList.class);
        // {E=class java.lang.String, E=class java.lang.String, T=class java.lang.String, E=class java.lang.String, E=class java.lang.String, E=class java.lang.String}
        // StringList 继承父类包括父接口列表,所以会有多个 E,并且同时指向了 java.lang.String 类对象
        // typeVariableTypeMap  包含了所有接口中的 TypeVariable 和 Type 的映射,简单地说,E 和 T 这类的,代表泛型参数,Type 代表具体的类型。
        System.out.println(typeVariableMap);
    }


    public static StringList getStringList() {
        return null;
    }

    public static ArrayList<Object> getList() { // 泛型参数类型具体化
        return null;
    }

    public static String getString() {
        return null;
    }

    /**
     *
     * @param containingClass Class类型
     * @param genericIfc 泛型接口类型
     * @param methodName 方法名
     * @param argumentTypes 方法参数
     * @throws NoSuchMethodException
     */
    private static void displayReturnTypeGenericInfo(Class<?> containingClass, Class<?> genericIfc, String methodName, Class... argumentTypes) throws NoSuchMethodException {

        // 根据方法名获取Method
        Method method = containingClass.getMethod(methodName, argumentTypes);

        // 声明类 GenericTypeResolverDemo.class 获取返回值类型
        Class<?> returnType = GenericTypeResolver.resolveReturnType(method, containingClass);

        // 常规类作为方法返回值
        System.out.printf("GenericTypeResolver.resolveReturnType(%s,%s) = %s\n", methodName, containingClass.getSimpleName(), returnType);
        // 常规类型不具备泛型参数类型 List 获取返回值类型的泛型
        Class<?> returnTypeArgument = GenericTypeResolver.resolveReturnTypeArgument(method, genericIfc);
        System.out.printf("GenericTypeResolver.resolveReturnTypeArgument(%s,%s) = %s\n", methodName, containingClass.getSimpleName(), returnTypeArgument);

    }

}

class StringList extends ArrayList<String> { // 泛型参数具体化(字节码有记录)
}
 
  

2、Spring 泛型集合类型辅助类

核心 API - org.springframework.core.GenericCollectionTypeResolver

版本支持:[2.0 , 4.3] (新版本的spring已经不用了)

替换实现:org.springframework.core.ResolvableType

处理 Collection 相关
• getCollection*Type

处理 Map 相关
• getMapKeyType
• getMapValue
Type

代码实例


import org.springframework.core.GenericCollectionTypeResolver;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * {@link GenericCollectionTypeResolver} 示例
 */
public class GenericCollectionTypeResolverDemo {

    private static StringList stringList;

    private static List<String> strings;

    public static void main(String[] args) throws Exception {

        // StringList extends ArrayList 具体化
        // getCollectionType 返回具体化泛型参数类型集合的成员类型 = String
        System.out.println(GenericCollectionTypeResolver.getCollectionType(StringList.class));

        System.out.println(GenericCollectionTypeResolver.getCollectionType(ArrayList.class));

        // 获取字段
        Field field = GenericCollectionTypeResolverDemo.class.getDeclaredField("stringList");
        System.out.println(GenericCollectionTypeResolver.getCollectionFieldType(field));

        field = GenericCollectionTypeResolverDemo.class.getDeclaredField("strings");
        System.out.println(GenericCollectionTypeResolver.getCollectionFieldType(field));
    }
}

3、Spring 方法参数封装

核心 API - org.springframework.core.MethodParameter

起始版本:[2.0 , )

元信息(部分)
• 关联的方法 - Method
• 关联的构造器 - Constructor
• 构造器或方法参数索引 - parameterIndex
• 构造器或方法参数类型 - parameterType
• 构造器或方法参数泛型类型 - genericParameterType
• 构造器或方法参数参数名称 - parameterName
• 所在的类 - containingClass

三、Spring 4.0泛型优化实现

1、ResolvableType

核心 API - org.springframework.core.ResolvableType
• 起始版本:[4.0 , )
• 扮演角色:GenericTypeResolver 和 GenericCollectionTypeResolver 替代者
• 工厂方法:for* 方法
• 转换方法:as* 方法
• 处理方法:resolve* 方法

源码分析

ResolvableType封装Java类型,提供对超类型、接口和泛型参数的访问,以及最终解析为类的能力。

Doc中有一个实例:

ResolvableType t = ResolvableType.forField(getClass().getDeclaredField("myMap"));
t.getSuperType(); // AbstractMap>
t.asMap(); // Map>
t.getGeneric(0).resolve(); // Integer
t.getGeneric(1).resolve(); // List
t.getGeneric(1); // List
t.resolveGeneric(1, 0); // String

代码实例

public class ResolvableTypeDemo {

    public static void main(String[] args) {
        // 工厂创建
        // StringList <- ArrayList <- AbstractList <- List <- Collection
        ResolvableType resolvableType = ResolvableType.forClass(StringList.class);

        resolvableType.getSuperType(); // ArrayList
        resolvableType.getSuperType().getSuperType(); // AbstractList

        System.out.println(resolvableType.asCollection().resolve()); // 获取 Raw Type(interface java.util.Collection)
        System.out.println(resolvableType.asCollection().resolveGeneric(0)); // 获取泛型参数类型(class java.lang.String)


    }
}

class StringList extends ArrayList<String> {
}

2、ResolvableType 的局限性

局限一:ResolvableType 无法处理泛型擦写

局限二:ResolvableType 无法处理非具体化的 ParameterizedType

3、ResolvableType 的设计优势

简化 Java 5 Type API 开发,屏蔽复杂 API 的运用,如 ParameterizedType

不变性设计(Immutability)

Fluent API 设计(Builder 模式),链式(流式)编程

参考资料

极客时间-《小马哥讲 Spring 核心编程思想》

你可能感兴趣的:(spring,boot,cloud,java,spring,jvm)