文章内容出自微信公众号:路人甲Java(后面附有原文地址),部分内容自己编写。
工欲善其事必先利其器。本系列分为两篇,此篇带大家了解一些泛型相关的接口和类,下篇为泛型实例。
泛型算是必须要掌握的一块硬核知识,很多地方都会用到,这块如果理解了。在阅读其他框架源码的时候会让你更容易一些。
关于泛型的解析上面,我们需要先了解一些接口和类,这些比较关键,这些都位于java.lang.reflect包中,类图如下:
下面一个个解释。
这是一个顶层接口,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方法,实现类也可以对这个方法重写。
所有声明泛型变量的公共接口,这个接口中定义了一个方法:
public interface GenericDeclaration extends AnnotatedElement {
/**
* Returns an array of {@code TypeVariable} objects that
* represent the type variables declared by the generic
* declaration represented by this {@code GenericDeclaration}
* object, in declaration order. Returns an array of length 0 if
* the underlying generic declaration declares no type variables.
*
* @return an array of {@code TypeVariable} objects that represent
* the type variables declared by this generic declaration
* @throws GenericSignatureFormatError if the generic
* signature of this generic declaration does not conform to
* the format specified in
* The Java™ Virtual Machine Specification
*/
public TypeVariable>[] getTypeParameters();
}
这个方法用于获取声明的泛型变量类型清单。
泛型变量可以在类和方法中进行声明,从上面的类图中也可以看出来:Java中任何类可以使用Class对象表示,方法可以使用Method类表示。从类图中还可知:Class类和Method类实现了GenericDeclaration接口,所以可以调用他们的**getTypeParameters()**方法获取其声明的泛型参数列表。
1、类中定义泛型变量类型
public class Demo1
上面代码表示了Demo1这个类中声明了3个泛型变量类型:T1、T2、T3,如果去调用这个类的Class对象中的getTypeParameters方法,可以获取到这三个泛型变量的信息。下篇再为大家实例演示。
2、方法中定义泛型变量类型
public T3 m1(T1 t1, T2 t2, T3 t3, String s){
return t3;
}
上面m1方法中声明了三个泛型类型变量:T1、T2、T3;Java中方法的任何信息都可以通过Method对象来获取,Method类实现了GenericDeclaration接口,所以Method类中实现了GenericDeclaration接口中的getTypeParameters方法,调用这个方法就可以获取m1方法中3个泛型变量类型的信息。下篇再为大家实例演示。
这个比较常见(反射机制),Class类的对象表示JVM中一个接口或类,每个Java对象被加载到JVM中都会表现为一个Class类型的对象。Java中数组也被映射为Class对象,所有元素类型相同且维数相同的数组都共享一个Class对象。通过Class对象可以获取接口或类中任何信息,比如:类名、类中声明的泛型信息、类的修饰符、类的父类信息、类的接口信息、类中的任何方法信息、类中任何字段信息等。
1、Class对象获取方式
在程序中,我们可以通过3种方式获取Class对象:
i、 类名.class
ii、 对象.getClass()
iii、Class.forName("类或接口的完整名称/权限定名")
2、常用方法
(1)、Field[] getFields()
这个方法会返回当前类以及其所有父类、父类的父类中所有public类型修饰的字段。
@CallerSensitive
public Field[] getFields() throws SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return copyFields(privateGetPublicFields(null));
}
(2)、Field[] getDeclaredFields()
这个方法会返回当前类中所有字段(和修饰符无关),也就是说不管这个字段是public还是private或者是protected,都会返回。有一点需要注意,只返回自己内部定义的字段,不包含其父类中的,这点需要注意,和getFields()是有区别的。
@CallerSensitive
public Field[] getDeclaredFields() throws SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
return copyFields(privateGetDeclaredFields(false));
}
(3)、Method[] getMethods()
这个方法会返回当前类的以及其所有父类的、父类的父类的、自己实现的接口、父接口继承的接口中的所有public类型的方法,需要注意一下,接口中的方法默认都是public类型的,接口中的方法public修饰符是可以省略的。
@CallerSensitive
public Method[] getMethods() throws SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return copyMethods(privateGetPublicMethods());
}
(4)、Method[] getDeclaredMethods()
返回当前类中定义的所有方法,不管这个方法修饰符是什么类型的,注意只包含自己内部定义的方法,不包含当前类的父类或者其实现的接口中定义的。
@CallerSensitive
public Method[] getDeclaredMethods() throws SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
return copyMethods(privateGetDeclaredMethods(false));
}
(5)、Type getGenericSuperclass()
返回父类的类型信息,如果父类是泛型类型,会返回超类中泛型的详细信息,这个方法比较关键,后面会有详细案例。
public Type getGenericSuperclass() {
ClassRepository info = getGenericInfo();
if (info == null) {
return getSuperclass();
}
// Historical irregularity:
// Generic signature marks interfaces with superclass = Object
// but this API returns null for interfaces
if (isInterface()) {
return null;
}
return info.getSuperclass();
}
(6)、TypeVariable
Class类继承了java.lang.reflect.GenericDeclaration接口,上面这个方法是在GenericDeclaration接口中定义的,Class类中实现了这个接口,用于返回当前类中声明的泛型变量参数列表。
public TypeVariable>[] getTypeParameters() {
ClassRepository info = getGenericInfo();
if (info != null)
return (TypeVariable>[])info.getTypeParameters();
else
return (TypeVariable>[])new TypeVariable>[0];
}
这个类用来表示Java中任何一个方法,通过这个类可以获取Java中方法的任何信息,比如:方法的修饰符、方法名称、方法的参数、方法的返回值、方法中声明的泛型参数列表等方法的一切信息。
常用方法
1、String getName()
用来获取方法的名称。
@Override
public String getName() {
return name;
}
2、Type[] getGenericParameterTypes()
返回方法的参数信息,如果参数是泛型类型,会返回泛型的详细信息。
@Override
public Type[] getGenericParameterTypes() {
return super.getGenericParameterTypes();
}
3、Type getGenericReturnType()
返回方法的返回值类型,如果返回值是泛型,会包含泛型的详细信息。
public Type getGenericReturnType() {
if (getGenericSignature() != null) {
return getGenericInfo().getReturnType();
} else { return getReturnType();}
}
4、TypeVariable< Method >[] getTypeParameters()
Method类继承了java.lang.reflect.GenericDeclaration接口,上面这个方法是在GenericDeclaration接口中定义的,Method类实现了这个接口,用于返回当前方法中声明的泛型变量参数列表。
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
public TypeVariable[] getTypeParameters() {
if (getGenericSignature() != null)
return (TypeVariable[])getGenericInfo().getTypeParameters();
else
return (TypeVariable[])new TypeVariable[0];
}
这个类用来表示Java中的字段,通过这个类可以获取Java中字段的任何信息,比如:字段的修饰符、字段名称、字段类型、泛型字段的类型等字段的一切信息。
常用方法
1、String getName()
获取字段的名称。
public String getName() {
return name;
}
2、Class> getType()
获取字段类型所属的Class对象。
public Class> getType() {
return type;
}
3、Type getGenericType()
获取字段的类型,如果字段是泛型,则返回泛型类型的详细信息;如果字段不是泛型,和getType返回的结果一样。
public Type getGenericType() {
if (getGenericSignature() != null)
return getGenericInfo().getGenericType();
else
return getType();
}
4、Class> getDeclaringClass()
获取这个字段是在哪个类中声明的,也就是当前字段所属的类。
public Class> getDeclaringClass() {
return clazz;
}
这个接口表示参数化类型,例如 List< String >、Map< Integer, String >、UserMapper< UserModel >这种带有泛型的类型。
常用方法
这个接口中定义了3个方法,都比较重要,我们一起来看看吧!
1、Type[] getActualTypeArguments()
获取泛型类型中的类型列表,就是<>中包含的参数列表。如:List< String >泛型类型列表只有一个是String;而Map< Integer, String >泛型类型中包含2个类型:Integer和String;UserMapper< UserModel >泛型类型为UserModel,实际上就是<>中间包含的类型列表。
2、Type getRawType()
返回参数化类型中的原始类型。比如:List< String >的原始类型为List;UserMapper< UserModel >原始类型为UserMapper,也就是<>符号前面的部分。
3、Type[] getOwnerType()
返回当前类型所属的类型。例如:存在A< T >类,其中定义了内部类InnerA< I >,则InnerA< I >所属的类型为A< I >,如果是顶层类型则返回null。这种关系比较常见的示例是Map
这个接口表示的是泛型变量,例如:List< T >中的T就是类型变量;而class C1
常用方法
1、Type[] getBounds
获取泛型变量的上边界,如果未明确上边界类型是什么,默认为Object。例如:Class Test< K extends Person > 中K的上边界只有一个,即Person;而class Test< T extends List & Interable >中T的上边界有2个,即List和Iterable;class Test< T >中T的上边界为Object。
2、D getGenericDeclaration()
获取声明该泛型变量的原始类型。例如:class Test< K extends Person >中的K为泛型变量,这个泛型变量是Test类定义的时候声明的,说明如果调用getGenericDeclaration方法返回的就是Test对象的Class对象。
还有,方法中也可以定义泛型类型的变量,如果在方法中定义,那么上面这个方法返回的就是定义泛型变量的方法了,返回的就是Method对象。
String getName()
获取在源码中定义时的名字。如:class Test< K extends Person >就是K;class Test1< T > 中就是T。
表示的是通配符泛型,通配符使用问号(?)表示。例如:? extends Number和 ?super Integer。
常用方法
1、Type[] getUpperBounds()
返回泛型变量的上边界列表。
3、Type[] getLowerBounds()
返回泛型变量的下边界列表。
表示的是数组类型,且数组中的元素是ParameterizedType或TypeVariable。
例如:List< String >[] 或者 T[]
这个接口只有一个方法:Type getGenericComponentType()
这个方法返回数组的组成元素。
上面的内容需要大家多看几遍,多理解多思考。下一篇就写案例,加深对上面内容的理解和应用,信息量比较大,请大家把这篇基础知识打牢哦。