Spring杂谈 您所在的位置:网站首页 类图示例 Spring杂谈

Spring杂谈

2023-04-14 22:39| 来源: 网络整理| 查看: 265

关于泛型的基本知识在本文中不会过多提及,本文主要解决的是如何处理泛型,以及java中Type接口下对泛型的一套处理机制,进而分析Spring中的ResolvableType。

文章目录Type简介接口定义UML类图ParameterizedType简介接口定义使用示例TypeVariable简介接口定义使用示例GenericArrayType简介接口定义使用示例WildcardType简介接口定义使用示例ResolvableType概览方法分析forClass系列方法forRawClass(Class clazz)forClass(Class clazz)forClass(Class baseType, Class implementationClass)forConstructor系列方法forMethod系列方法forMethodParameterforMethodReturnTypeforConstructor系列方法forField系列方法forType系列(源码分析)总结

Type 简介

Type是Java 编程语言中所有类型的公共高级接口(官方解释),也就是Java中所有类型的“爹”;其中,“所有类型”的描述尤为值得关注。它并不是我们平常工作中经常使用的 int、String、List、Map等数据类型,而是从Java语言角度来说,对基本类型、引用类型向上的抽象;

Type体系中类型的包括:原始类型(Class)、参数化类型(ParameterizedType)、数组类型(GenericArrayType)、类型变量(TypeVariable)、基本类型(Class);

原始类型,不仅仅包含我们平常所指的类,还包括枚举、数组、注解等;

参数化类型,就是我们平常所用到的泛型List、Map这种;

数组类型,并不是我们工作中所使用的数组String[] 、byte[],而是带有泛型的数组,即T[] ;

基本类型,也就是我们所说的java的基本类型,即int,float,double等

Type体系的出现主要是为了解决泛型的一系列问题。

接口定义 public interface Type {// 返回这个类型的名称default String getTypeName() {return toString();} }

可以看到Type接口内只定义了一个方法,这个方法会返回该类型的名称

UML类图

在这里插入图片描述 在上面的图中对于Class我相信大家都已经很了解了。我们主要对其余四个子接口进行测试分析

ParameterizedType 简介

参数化类型,也就是我们所说的泛型。像List就是一个参数化类型,但是List并不是,因为没有使用泛型。

接口定义 public interface ParameterizedType extends Type {// 对于一个参数化类型而言,必定是带有泛型的,所有这里是为了获取到其中的泛型的具体类型,也就是中的内容// 返回一个数组是因为,有时候会定义多个泛型,比如MapType[] getActualTypeArguments();// 获取原始类型,这里不带泛型,就是classType getRawType();// 获取这个类所在类的类型,这里可能比较拗口,举个例子,假如当前这个ParameterizedType的类型为// O.I,那么调用这个方法所返回的就是一个O类型Type getOwnerType(); } 使用示例 public class Main extends OwnerTypeDemo {private List stringList;private Map stringStringMap;private Map.Entry entry;private OwnerTypeDemo.Test testOwnerType;private List list;private Map map;public void test(List stringList, List list) {}public static void main(String[] args) {Class mainClass = Main.class;Field[] fields = mainClass.getDeclaredFields();for (Field field : fields) {Type genericType = field.getGenericType();String typeName = genericType.getTypeName();String name = field.getName();if (genericType instanceof ParameterizedType) {System.out.println(name + "是一个参数化类型,类型名称为:" + typeName);ParameterizedType parameterizedType = (ParameterizedType) genericType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();System.out.println(name + "的actualTypeArguments:" + Arrays.toString(actualTypeArguments));Type ownerType = parameterizedType.getOwnerType();System.out.println(name + "的ownerType:" + ownerType);Type rawType = parameterizedType.getRawType();System.out.println(name + "的rawType:" + rawType);} else {System.out.println(name + "不是一个参数化类型,类型名称为:" + typeName);}}System.out.println("===================开始测试方法中的参数=========================");Method[] declaredMethods = mainClass.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {String methodName = declaredMethod.getName();Type[] genericParameterTypes = declaredMethod.getGenericParameterTypes();for (int i = 0; i System.out.println("第" + (i + 1) + "个参数是一个参数化类型, 类型名称为 : " + typeName);} else {System.out.println("第" + (i + 1) + "个参数不是一个参数化类型, 类型名称为 : " + typeName);}}}System.out.println("===================开始测试父类中的泛型=========================");// 获取带有泛型的父类Type genericSuperclass = mainClass.getGenericSuperclass();if (genericSuperclass instanceof ParameterizedType) {System.out.println("父类是一个参数化类型,类型名称为:" + genericSuperclass.getTypeName());}} }class OwnerTypeDemo {class Test {} }

程序会做如下输出:

stringList是一个参数化类型,类型名称为:java.util.List stringList的actualTypeArguments:[class java.lang.String] stringList的ownerType:null stringList的rawType:interface java.util.List stringStringMap是一个参数化类型,类型名称为:java.util.Map stringStringMap的actualTypeArguments:[class java.lang.String, class java.lang.String] stringStringMap的ownerType:null stringStringMap的rawType:interface java.util.Map entry是一个参数化类型,类型名称为:java.util.Map$Entry entry的actualTypeArguments:[class java.lang.String, ?] entry的ownerType:interface java.util.Map entry的rawType:interface java.util.Map$Entry testOwnerType是一个参数化类型,类型名称为:main.java.OwnerTypeDemo$Test testOwnerType的actualTypeArguments:[class java.lang.String] testOwnerType的ownerType:main.java.OwnerTypeDemo testOwnerType的rawType:class main.java.OwnerTypeDemo$Test list不是一个参数化类型,类型名称为:java.util.List map不是一个参数化类型,类型名称为:java.util.Map ===================开始测试方法中的参数========================= 打印main方法的参数,第1个参数为:class [Ljava.lang.String; 第1个参数不是一个参数化类型, 类型名称为 : java.lang.String[] 打印test方法的参数,第1个参数为:java.util.List 第1个参数是一个参数化类型, 类型名称为 : java.util.List 打印test方法的参数,第2个参数为:interface java.util.List 第2个参数不是一个参数化类型, 类型名称为 : java.util.List ===================开始测试父类中的泛型========================= 父类是一个参数化类型,类型名称为:main.java.OwnerTypeDemo

通过上面的例子可以看出,ParameterizedType可以让我们明确字段或者方法参数上是否使用了泛型,并获取到泛型的具体类型。那是不是依赖ParameterizedType就能解决所有的泛型问题了呢?答案显然是不是的,我们看一个特殊的例子:

public class SpecialDemo {T t;public static void main(String[] args) {Class specialDemoClass = SpecialDemo.class;Field[] declaredFields = specialDemoClass.getDeclaredFields();for (Field declaredField : declaredFields) {Type genericType = declaredField.getGenericType();if (genericType instanceof ParameterizedType) {System.out.println("t是一个参数化类型");} else {System.out.println("t不是一个参数化类型");}}}// 程序输出:t不是一个参数化类型 }

运行上面的程序,会发现字段t不是一个参数化类型,这就意味着没办法通过ParameterizedType来解决这一类泛型问题。我们分析,会发现其实T类似于一个变量,我们可以在使用时可以传入具体的类,比如我们可以这样:

SpecialDemo specialDemo = new SpecialDemo();

同时这个基于这个表达式,我们知道这个变量是具有属性的,最直观的就是T是有上界的,所有的T都继承了Type。基于这种情况,Java对其进行了抽象,得到了一个新的类型TypeVariable。

TypeVariable 简介

类型变量,或者也可以叫泛型变量。具体就是指我们在申明泛型时定义的T,K,U这种变量。在之前的例子中,SpecialDemo,T就是一个类型变量。

接口定义 public interface TypeVariable extends Type, AnnotatedElement {// 获取泛型的边界Type[] getBounds();// 获取申明所在的具体对象D getGenericDeclaration();// 获取具体类型变量的名称String getName();// 获取类型变量边界上添加的注解AnnotatedType[] getAnnotatedBounds(); }

可以看到,TypeVariable本身也使用了泛型,并且泛型的上界为GenericDeclaration。在了解TypeVariable之前,有必要先对GenericDeclaration做一个简单的说明。GenericDeclaration这个接口主要限定了哪些地方可以定义TypeVariable,换言之,也就是定义了哪些地方可以申明泛型。这个接口只有3个实现类(忽略Executable抽象类)。如下:

在这里插入图片描述

从这里我们也能看到,我们只能在方法(包括普通方法跟构造方法)以及类上申明泛型。

这里需要对接口定义的方法做进一步的说明:

getBounds()会返回泛型的边界,但是这里的边界跟我们在参数化类型中定义的边界不同,这里的边界只有上界。即我们不通通过super关键字来申明一个泛型,例如下面这种: class A{}

在申明泛型时,我们要明确一点,申明是为了使用,而在上面的例子中,我们不能使用T来干任何事情,因为我们不能确定T中的任何方法(只能确定它是一个Object,但是这没有任何意义)。所以对于泛型变量来说,只存在上界,也就是只能使用extends关键字进行申明

getGenericDeclaration(),返回泛型申明时所在的类或者方法返回泛型变量的名称,也就是我们定义泛型时采用的T,K,U这一类的名称getAnnotatedBounds(),此方法返回一个AnnotatedType类型的数组,获取的是我们在类型变量的上界。不同于getBounds()方法的是,这个方法可以获取到边界上添加的注解 使用示例 public class TypeVariableMain {public void testTypeVariable(Map map) {}public static void main(String[] args) {Class typeVariableMainClass = TypeVariableMain.class;TypeVariable[] typeParameters = typeVariableMainClass.getTypeParameters();for (int i = 0; i Annotation[] annotations = annotatedType.getAnnotations();if (annotations.length > 0) {System.out.println("第" + (i + 1) + "个类型变量的上界上添加了注解,注解为" + annotations[0]);}}}System.out.println("===================基于方法获取类型变量====================");Method[] declaredMethods = typeVariableMainClass.getDeclaredMethods();for (Method declaredMethod : declaredMethods) {String methodName = declaredMethod.getName();if (methodName.equals("main")) {// 为了方便,直接排除main函数了continue;}TypeVariable[] typeVariables = declaredMethod.getTypeParameters();int i = 1;for (TypeVariable typeVariable : typeVariables) {System.out.println("方法:\"" + methodName + "\"的第" + (i++) + "个类型变量为" + typeVariable.getName());}}} }

程序打印如下:

第1个类型变量的名称为:T 通过getBounds方法获取到,第1个类型变量的边界为:[class java.lang.Object] 第1个类型变量的申明的位置为:class main.java.TypeVariableMain 通过getAnnotatedBounds方法获取到,第1个类型变量的边界为:[class java.lang.Object] 第2个类型变量的名称为:K 通过getBounds方法获取到,第2个类型变量的边界为:[class java.lang.Integer, interface java.lang.reflect.Type] 第2个类型变量的申明的位置为:class main.java.TypeVariableMain 通过getAnnotatedBounds方法获取到,第2个类型变量的边界为:[class java.lang.Integer, interface java.lang.reflect.Type] 第2个类型变量的上界上添加了注解,注解为@main.java.TypeAnnotation() ===================基于方法获取类型变量==================== 方法:"testTypeVariable"的第1个类型变量为U 方法:"testTypeVariable"的第2个类型变量为V

为了让大家加深对ParameterizedType以及TypeVariable理解,这里我额外添加一个Demo

public class TypeVariableMain02 {private K k;private List list;public static void main(String[] args) {Class typeVariableMain02Class = TypeVariableMain02.class;Field[] declaredFields = typeVariableMain02Class.getDeclaredFields();for (Field field : declaredFields) {Type genericType = field.getGenericType();String typeName = genericType.getTypeName();String name = field.getName();if (genericType instanceof ParameterizedType) {System.out.println(name + "是一个参数化类型,类型名称为:" + typeName);ParameterizedType parameterizedType = (ParameterizedType) genericType;Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();System.out.println(name + "的actualTypeArguments:" + Arrays.toString(actualTypeArguments));Type ownerType = parameterizedType.getOwnerType();System.out.println(name + "的ownerType:" + ownerType);Type rawType = parameterizedType.getRawType();System.out.println(name + "的rawType:" + rawType);for (Type actualTypeArgument : actualTypeArguments) {if (actualTypeArgument instanceof TypeVariable) {System.out.println("字段:" + name + "中包含一个类型变量");String name1 = ((TypeVariable) actualTypeArgument).getName();AnnotatedType[] annotatedBounds = ((TypeVariable) actualTypeArgument).getAnnotatedBounds();Type[] bounds = ((TypeVariable) actualTypeArgument).getBounds();GenericDeclaration genericDeclaration = ((TypeVariable) actualTypeArgument).getGenericDeclaration();System.out.println("类型变量的名称为:" + name1);System.out.println("个类型变量的边界为:" + Arrays.toString(bounds));System.out.println("类型变量的申明的位置为:" + genericDeclaration);System.out.println("通过getAnnotatedBounds方法获取到,类型变量的边界为:" + annotatedBounds[0].getType());}}} else if (genericType instanceof TypeVariable) {System.out.println(name + "是一个类型变量,类型名称为:" + typeName);TypeVariable typeVariable = (TypeVariable) genericType;Type[] bounds = typeVariable.getBounds();String name1 = typeVariable.getName();AnnotatedType[] annotatedBounds = typeVariable.getAnnotatedBounds();GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();System.out.println("类型变量的名称为:" + name1);System.out.println("个类型变量的边界为:" + Arrays.toString(bounds));System.out.println("类型变量的申明的位置为:" + genericDeclaration);System.out.println("通过getAnnotatedBounds方法获取到,类型变量的边界为:" + annotatedBounds[0].getType() + " " + annotatedBounds[1].getType());}}} }

程序输出:

k是一个类型变量,类型名称为:K 类型变量的名称为:K 个类型变量的边界为:[class java.lang.Integer, interface java.lang.reflect.Type] 类型变量的申明的位置为:class main.java.TypeVariableMain02 通过getAnnotatedBounds方法获取到,类型变量的边界为:class java.lang.Integer interface java.lang.reflect.Type list是一个参数化类型,类型名称为:java.util.List list的actualTypeArguments:[T] list的ownerType:null list的rawType:interface java.util.List 字段:list 中包含一个类型变量 类型变量的名称为:T 个类型变量的边界为:[class java.lang.Object] 类型变量的申明的位置为:class main.java.TypeVariableMain02 通过getAnnotatedBounds方法获取到,类型变量的边界为:class java.lang.Object GenericArrayType 简介

GenericArrayType是Type的子接口,用于表示“泛型数组”,描述的是形如:A[]或T[]的类型。其实也就是描述ParameterizedType类型以及TypeVariable类型的数组,即形如:classA[][]、T[]等

接口定义 public interface GenericArrayType extends Type {// 返回数组中元素的类型,TypeVariable或者ParameterizedTypeType getGenericComponentType(); } 使用示例 public class GenericArrayTypeMain {T[] t1;T[][] t2;List list;List[] stringListArray;String[][] stringArray;public static void main(String[] args) {Class genericArrayTypeMainClass = GenericArrayTypeMain.class;Field[] declaredFields = genericArrayTypeMainClass.getDeclaredFields();for (Field declaredField : declaredFields) {String name = declaredField.getName();Type genericType = declaredField.getGenericType();if (genericType instanceof GenericArrayType) {System.out.println(name + "是一个泛型数组");Type genericComponentType = ((GenericArrayType) genericType).getGenericComponentType();System.out.println("数组的元素类型为:" + genericComponentType);} else {System.out.println(name + "不是一个泛型数组");}}} }

程序输出:

t1是一个泛型数组 数组的元素类型为:T t2是一个泛型数组 数组的元素类型为:T[] list不是一个泛型数组 stringListArray是一个泛型数组 数组的元素类型为:java.util.List stringArray不是一个泛型数组

通过上面的Demo我们会发现,无论从左向右有几个[]并列,这个方法仅仅脱去最右边的[]之后剩下的内容就作为这个方法的返回值。

另外,在上面的例子中,大家可以思考以下几个问题:

t1是一个泛型数组,数组的元素类型为:T,那么T是一个什么类型呢?t2是一个泛型数组,数组的元素类型为:T[],那么T[]又是什么类型?

上述问题留给大家自行思考

了解了ParameterizedType跟TypeVariable以及这两种类型的数组类型GenericArrayType之后,接着我们思考一个问题,我们在定义泛型时,经常会使用来通配符,形如下面这种形式{? extends Number},这个时候即使我们获取到? extends Number也没有办法做进一步的处理。这个时候就要用到我们接下来要介绍的这个接口了,请往下看

WildcardType 简介

专门用来处理泛型中的通配符,需要注意的是,WildcardType并不是JAVA所有类型中的一种,表示的仅仅是类似 {? extends T}、{? super K}这样的通配符表达式。

接口定义 public interface WildcardType extends Type {// 获取通配符表达式的上界Type[] getUpperBounds();// 获取通配符表达式的下界Type[] getLowerBounds();}

上面这两个方法之所以会返回数组是为了保持扩展性,实际上现在返回的数组的大小就是1,JDK8中至少是这样的吗,更高版本的没有去尝试。

使用示例 public class WildcardTypeDemo {Map map;public static void main(String[] args) {Class wildcardTypeDemoClass = WildcardTypeDemo.class;Field[] declaredFields = wildcardTypeDemoClass.getDeclaredFields();for (Field field : declaredFields) {Type genericType = field.getGenericType();if (genericType instanceof ParameterizedType) {// 使用了通配符表达泛型的,必定是一个参数化类型// 获取泛型的实际类型,就是获取中的内容,这里获取到的是


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有