Java-Generic-Type
本文主要讲解泛型类型的解析,泛型算是必须要掌握的一块硬核知识,在很多地方都会用到,这块如果理解了,在阅读其他框架源码的时候会让你更容易一些,看完本文之后大家对泛型也有一个新的认识。
关于泛型的解析上面,我们需要先了解一些类和接口,这些比较关键,这些都位于java.lang.reflect包中,类图如下:
图片
下面一个个来解释。
Type接口
这是一个顶层接口,java中的任何类型都可以用这个来表示,这个接口是Java编程语言中所有类型的公共超接口。这些类型包括原始类型、泛型类型、泛型变量类型、通配符类型、泛型数组类型、数组类型等各种类型。
这个接口代码比较简单,源码:
public interface Type {
/**
* Returns a string describing this type, including information
* about any type parameters.
*
* @implSpec The default implementation calls {@code toString}.
*
* @return a string describing this type
* @since 1.8
*/
default String getTypeName() {
return toString();
}
}
这个接口只有一个方法getTypeName,用于返回具体类型的名称,是一个默认方法,默认会调用当前类的toString方法,实现类也可以对这个方法重写。
GenericDeclaration接口
所有声明泛型变量的公共接口,这个接口中定义了一个方法:
public TypeVariable<?>[] getTypeParameters()
这个方法用于获取声明的泛型变量类型清单。
泛型变量可以在类和方法中进行声明,从上面类图中也可以看出来,java中任何类可以使用Class对象表示,方法可以用Method类表示,类图中可以知,Class类和Method类实现了GenericDeclaration接口,所以可以调用他们的getTypeParameters方法获取其声明的泛型参数列表。
类中定义泛型变量类型
public class Demo1<T1, T2 extends Integer, T3 extends Demo1I1 & Demo1I2>
上面代码表示Demo1这个类中声明了3个泛型变量类型:T1、T2、T3,所以如果去调用这个类的Clas对象中的getTypeParameters方法可以获取到这三个泛型变量的信息,文章后面有案例演示。
方法中定义泛型变量类型
public <T1, T2 extends Integer, T3 extends Demo2I1 & Demo2I2> T3 m1(T1 t1, T2 t2, T3 t3, String s) {
return t3;
}
上面m1方法中声明了三个泛型类型变量:T1、T2、T3;java中可以方法的任何信息都可以通过Method对象来获取,Mehod类实现了GenericDeclaration接口,所以Method类中实现了GenericDeclaration接口中的getTypeParameters方法,调用这个方法就可以获取m1方法中3个泛型变量类型的信息,文章后面有案例演示。
Class类
这个比较常见,Class类的对象表示JVM中一个类或者接口,每个java对象被加载到jvm中都会表现为一个Class类型的对象,java中的数组也被映射为Class对象,所有元素类型相同且维数相同的数组都共享一个class对象,通过Class对象可以获取类或者接口中的任何信息,比如:类名、类中声明的泛型信息、类的修饰符、类的父类信息、类的接口信息、类中的任何方法信息、类中任何字段信息等等。
Class对象获取方式
在程序中我们可以通过3中方式获取Class对象:
类名.class对象.getClass()Class.forName("类或者接口的完整名称")
常用的方法
Field[] getFields()
这个方法会返回当前类的以及其所有父类、父类的父类中所有public类型的字段。
Field[] getDeclaredFields()
这个方法会返回当前类中所有字段(和修饰符无关),也就说不管这个字段是public还是private或者是protected,都会返回,有一点需要注意,只返回自己内部定义的字段,不包含其父类中的,这点需要注意,和getFields是有区别的。
Method[] getMethods()
这个方法会返回当前类的以及其所有父类的、父类的父类的、自己实现的接口、父接口继承的接口中的所有public类型的方法,需要注意一下,接口中的方法默认都是public类型的,接口中的方法public修饰符是可以省略的。
Method[] getDeclaredMethods()
返回当前类中定义的所有方法,不管这个方法修饰符是什么类型的,注意只包含自己内部定义的方法,不包含当前类的父类或者其实现的接口中定义的。
Type getGenericSuperclass()
返回父类的类型信息,如果父类是泛型类型,会返回超类中泛型的详细信息,这个方法比较关键,后面会有详细案例。
TypeVariable<Class<T>>[] getTypeParameters()
Class类继承了java.lang.reflect.GenericDeclaration接口,上面这个方法是在GenericDeclaration接口中定义的,Class类中实现了这个接口,用于返回当前类中声明的泛型变量参数列表。
Method类
这个类用来表示java中的任何一个方法,通过这个类可以获取java中方法的任何信息,比如:方法的修饰符、方法名称、方法的参数、方法返回值、方法中声明的泛型参数列表等方法的一切信息。
常用的方法
String getName()
用来获取方法的名称。
Type[] getGenericParameterTypes()
返回方法的参数信息,如果参数是泛型类型的,会返回泛型的详细信息,这个方法后面会演示。
Type getGenericReturnType()
返回方法的返回值类型,如果返回值是泛型的,会包含泛型的详细信息。
TypeVariable<Method>[] getTypeParameters()
Method类继承了java.lang.reflect.GenericDeclaration接口,上面这个方法是在GenericDeclaration接口中定义的,Method类中实现了这个接口,用于返回当前方法中声明的泛型变量参数列表。
Field类
这个类用来表示java中的字段,通过这个类可以获取java中字段的任何信息,比如:字段的修饰符、字段名称、字段类型、泛型字段的类型等字段的一切信息。
常用的方法
String getName()
获取字段的名称。
Class<?> getType()
获取字 段类型所属的Class对象。
Type getGenericType()
获取字段的类型,如果字段是泛型类型的,会返回泛型类型的详细信息;如果字段不是泛型类型的,和getType返回的结果是一样的。
Class<?> getDeclaringClass()
获取这个字段是在哪个类中声明的,也就是当前字段所属的类。
ParameterizedType接口
这个接口表示参数化类型,例如List<String>、Map<Integer,String>、UserMapper<UserModel>这种带有泛型的类型。
常用方法
这个接口中定义了3个方法,都比较重要,来看一下。
Type[] getActualTypeArguments()
获取泛型类型中的类型列表,就是<>中包含的参数列表,如:List<String>泛型类型列表只有一个是String,而Map<Integer,String>泛型类型中包含2个类型:Integer和String,UserMapper<UserModel>泛型类型为UserModel,实际上就是<和>中间包含的类型列表。
Type getRawType()
返回参数化类型中的原始类型,比如:List<String>的原始类型为List,UserMapper<UserModel>原始类型为UserMapper,也就是<符号前面的部分。
Type[] getOwnerType()
返回当前类型所属的类型。例如存在A<T>类,其中定义了内部类InnerA<I>,则InnerA<I>所属的类型为A<I>,如果是顶层类型则返回null。这种关系比较常见的示例是Map<K,V>接口与Map.Entry<K,V>接口,Map<K,V>接口是Map.Entry<K,V>接口的所有者。
TypeVariable接口
这个接口表示的是泛型变量,例如:List<T>中的T就是类型变量;而class C1<T1,T2,T3>{}表示一个类,这个类中定义了3个泛型变量类型,分别是T1、T2和T2,泛型变量在java中使用TypeVariable接口来表示,可以通过这个接口提供的方法获取泛型变量类型的详细信息。
常用的方法
Type[] getBounds()
获取泛型变量类型的上边界,如果未明确什么上边界默认为Object。例如:class Test<K extend Person>中K的上边界只有一个,是Person;而class Test<T extend List & Iterable>中T的上边界有2个,是List和Iterable
D getGenericDeclaration()
获取声明该泛型变量的原始类型,例如:class Test<K extend Person>中的K为泛型变量,这个泛型变量时Test类定义的时候声明的,说明如果调用getGenericDeclaration方法返回的就是Test对应的Class对象。
还有方法中也可以定义泛型类型的变量,如果在方法中定义,那么上面这个方法返回的就是定义泛型变量的方法了,返回的就是Method对象。
String getName()
获取在源码中定义时的名字,如:class Test<K extend Person>就是K;class Test1<T>中就是T。
WildcardType接口
表示的是通配符泛型,通配符使用问号表示,例如:? extends Number和? super Integer。
常用方法
接口中定义了2个方法。
Type[] getUpperBounds()
返回泛型变量的上边界列表。
Type[] getLowerBounds()
返回泛型变量的下边界列表。
GenericArrayType接口
表示的是数组类型,且数组中的元素是ParameterizedType或者TypeVariable。
例如:List<String>[]或者T[]。
常用方法
这个接口只有一个方法:
Type getGenericComponentType()
这个方法返回数组的组成元素。
上面的大家多看几遍,下面开始上案例,加深对上面的理解和应用,信息量会比较大,慢慢理解。
泛型变量
泛型变量可以在类中和方法中定义。
泛型变量类型的使用TypeVariable接口来表示,所以可以通过TypeVariable接口获取泛型变量的所有信息。
下面我们分别来看看类中定义泛型变量和方法中定义泛型变量的用法以及泛型变量信息的获取。
类中定义泛型变量
语法
class 类名<泛型变量1,泛型变量2,泛型变量3 extends 上边界1,泛型变量4 extends 上边界类型1 & 上边界类型2 & 上边界类型3>