相关文章:
本文主要介绍获取泛型超类和泛型接口的相关信息;Type
的分类以及在泛型超类和泛型接口中的使用案例。
这部分内容不是很好理解,需要好好消化消化。这部分内容算是反射里比较难懂的部分,有必要好好学习掌握,这样才能在阅读源码时更加顺畅。
在上篇文章 Java筑基——反射(1):基本类周边信息获取中,我们介绍了
// 获取 Class 对象的普通类型父类
public native Class<? super T> getSuperclass();
但是没有介绍:
// 获取 Class 对象的泛型类型父类
public Type getGenericSuperclass()
这里,我们会重点介绍这个方法的使用。
先介绍一下用于演示的类:
Holder
类,是一个泛型类,它有一个类型参数是 T
:
public class Holder<T> {
public T t;
public Holder(T t) {
this.t = t;
}
}
为了使 Holder
类看起来简洁,我特意省略了 getter/setter 方法。
IntegerHolder
类, 是一个普通类,它继承于 Holder
,并且给 Holder
的泛型类型参数传递了 Integer
这个实际类型:
public class IntegerHolder extends Holder<Integer>{
public IntegerHolder(Integer integer) {
super(integer);
}
}
准备工作就绪,开始代码测试:
Type type = IntegerHolder.class.getGenericSuperclass();
System.out.println("type = " + type);
在这里,调用 IntegerHolder
对应的 Class
对象上的 getGenericSuperclass()
,获取到的是一个 Type
类型的对象。并且打印了 Type
对象的信息。
查看打印结果:
type = com.java.advanced.features.reflect.genericsclass.blog.Holder
可以看到,通过 getGenericSuperclass()
获取到的 Type
对象里不仅仅包含了 IntegerHolder
的超类 Holder
的信息,还包括了实际类型参数 Integer
。
作为对比,getSuperclass()
方法只能获取到 IntegerHolder
的超类 Holder
而已。
Class<? super IntegerHolder> superclass = IntegerHolder.class.getSuperclass();
System.out.println("superclass = " + superclass);
打印结果:
superclass = class com.java.advanced.features.reflect.genericsclass.blog.Holder
到这里,有没有同学会想 Type
是什么?如何分别获取超类信息和实际类型参数的信息?
我们去查一下文档的说明:
可以看到 Type
是一个接口,从 1.5 开始引入的,它有 4 个子接口:GenericArrayType
,ParameterizedType
,TypeVariable
,WildcardType
;1 个实现类:Class
。
类图如下:
类图中列出了各个子接口以及子接口的方法,希望大家有一个整体的概念。但是,在这里,还不会一一去介绍。我们会在 2.2 中详细介绍 Type
的使用。
回到我们这个小节里,现在我们已经知道了 Type
是什么;接着看如何分别获取超类信息和实际类型参数的信息?
请看下面的测试代码如下:
public class _01_GetGenericSuperClassTest {
public static void main(String[] args) {
Type type = IntegerHolder.class.getGenericSuperclass();
System.out.println("type = " + type);
if (type instanceof ParameterizedType) {
// 把 Type 类型强制类型转换为 ParameterizedType 类型
ParameterizedType parameterizedType = (ParameterizedType) type;
// 获取替换了泛型类型参数的实际类型的 Type 对象的数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
Class typeArgument = (Class) actualTypeArgument;
System.out.println("替换泛型类型参数的实际类型为:" + typeArgument.getName());
}
// 获取声明了泛型类型的原始类型
Type rawType = parameterizedType.getRawType();
Class rawClass = (Class) rawType;
System.out.println("声明了泛型类型的原始类型为:" + rawClass.getName());
}
}
}
打印结果:
type = com.java.advanced.features.reflect.genericsclass.blog.Holder
替换泛型类型参数的实际类型为:java.lang.Integer
声明了泛型类型的原始类型为:com.java.advanced.features.reflect.genericsclass.blog.Holder
可以看到,代码中通过了 type instanceof ParameterizedType
判断,说明 type
是 ParameterizedType
的一个实例,再看一下 type
的打印是 Holder
,它是一个泛型类型,对应的是 ParameterizedType
。
然后,我们通过调用 ParameterizedType
的两个方法:
Type[] getActualTypeArguments();
Type getRawType();
第一个方法是获取替换了泛型类型参数的实际类型的 Type
对象的数组。这个方法里,我们需要注意的是,返回的是一个数组,而且数组的元素也是 Type
类型的。
这是为什么呢?返回一个数组是因为泛型类型参数可以有多个,就像一个方法可以声明多个形式参数一样。数组的元素类型是 Type
,这是因为不仅仅是 Class
用于替换类型参数,其他的 Type
子接口也可以。
第二个方法是获取声明了泛型类型的原始类型。需要注意的一点是“原始类型"的概念一定是和泛型类型在一起的。如果不是泛型类型,那么就无所谓原始类型。
在上篇文章 Java筑基——反射(1):基本类周边信息获取中,我们介绍了
// 获取 Class 对象的直接继承或实现的接口的 Class 对象列表
public Class<?>[] getInterfaces()
但是没有介绍:
// 获取 Class 对象的直接继承或实现的泛型接口 Class 对象列表
public Type[] getGenericInterfaces()
本小节,我们会重点介绍这个方法的使用。
先介绍一下,参与测试的类:
Generator
是一个泛型接口,定义了一个生成器,定义一个 next()
方法:
public interface Generator<T> {
T next();
}
IntegerGenerator
实现了 Generator
接口和 Serializable
接口,使用 Integer
替换泛型接口 Generator
的类型参数:
public class IntegerGenerator implements Generator<Integer>, Serializable {
Random random = new Random();
@Override
public Integer next() {
return random.nextInt();
}
}
下面看测试代码:
Type[] types = IntegerGenerator.class.getGenericInterfaces();
for (Type type : types) {
System.out.println("type = " + type);
}
打印结果:
type = com.java.advanced.features.reflect.genericsclass.blog.Generator
type = interface java.io.Serializable
可以看到,getGenericInterfaces()
不仅可以获取泛型类型的超类接口,还可以获取普通类型的超类接口。
和 2.1.1 中同样地,我们对获取到的 Type
对象进一步拆分出需要的信息。
测试代码如下:
public class _02_GetGenericInterfacesTest {
public static void main(String[] args) {
Type[] types = IntegerGenerator.class.getGenericInterfaces();
for (Type type : types) {
System.out.println("type = " + type);
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
Class typeArgument = (Class) actualTypeArgument;
System.out.println("替换泛型类型参数的实际类型为: " + typeArgument);
}
Type rawType = parameterizedType.getRawType();
Class rawClass = (Class) rawType;
System.out.println("声明了泛型接口的原始类型为: " + rawClass);
}
}
}
}
打印信息:
type = com.java.advanced.features.reflect.genericsclass.blog.Generator
替换泛型类型参数的实际类型为: class java.lang.Integer
声明了泛型接口的原始类型为: interface com.java.advanced.features.reflect.genericsclass.blog.Generator
type = interface java.io.Serializable
在 2.1 中,演示了 ParameterizedType
和 Class
的使用,本节会演示 TypeVariable
,GenericArrayType
和 WildcardType
的使用。
ParameterizedType
表示参数化类型,如 Collection
。
文档上的定义是,TypeVariable
是各种类型变量的公共高级接口。可是看了之后,还是不能明白。
我们可以这样理解:当获取到的 Type
对象表示是一个泛型的类型参数时,它就是 TypeVariable
。
下面我们仍是会通过代码演示。
首先,定义一个 NumberGenerator
泛型接口,它有一个泛型类型参数 T
,限定为 Number
及其子类型;NumberGenerator
接口继承于 Generator
接口。
public interface NumberGenerator<T extends Number> extends Generator<T>{
}
测试代码如下:
public class _03_TypeVariableTest {
public static void main(String[] args) {
// 获取此接口直接继承的接口对应的 Type 对象数组
Type[] types = NumberGenerator.class.getGenericInterfaces();
for (Type type : types) {
System.out.println("type = " + type); // 打印:Generator
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
// 获取替换了泛型类型参数的实际类型的 Type 对象数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
if( actualTypeArgument instanceof TypeVariable) {
TypeVariable typeVariable = (TypeVariable) actualTypeArgument;
System.out.println("泛型类型参数的名字为 " + typeVariable.getName()); // 打印:T
Type[] bounds = typeVariable.getBounds();
for (Type bound : bounds) {
Class boundClass = (Class) bound;
System.out.println("泛型类型参数的上界为:" + boundClass.getName()); // 打印:java.lang.Number
}
}
}
}
}
}
}
打印结果:
type = com.java.advanced.features.reflect.genericsclass.blog.Generator
泛型类型参数的名字为 T
泛型类型参数的上界为:java.lang.Number
上面的测试代码看着可能觉得有点多,我们一点一点来看,肯定能够全部理解的。
首先,看获取 ParameterizedType
的部分:
// 获取此接口直接继承的接口对应的 Type 对象数组
Type[] types = NumberGenerator.class.getGenericInterfaces();
for (Type type : types) {
System.out.println("type = " + type); // 打印:Generator
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
大家不要去想 for-each 循环,我们这里 types
数组的长度就是 1,因为 NumberGenerator
直接继承的接口只有一个,就是 Generator
。
看一下这里获取到的 type
的值:
type = com.java.advanced.features.reflect.genericsclass.blog.Generator
Generator
说明 type
是一个泛型类型,即参数化类型,对应的是 ParameterizedType
。因此,可以通过 type instanceof ParameterizedType
的条件判断,进而把 type
强制类型转换为 ParameterizedType
类型。
接着,调用 getActualTypeArguments()
方法,获取替换了泛型类型参数的实际类型的 Type
对象数组:
// 获取替换了泛型类型参数的实际类型的 Type 对象数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
我们这里 parameterizedType
,即对应 Generator
。其实,这里并没有使用实际类型替换泛型类型参数,只是传入了一个类型参数而已。
因为 Generator
只有一个类型参数,所以 actualTypeArguments
数组的长度是 1。
最后,看 TypeVariable
的部分:
if( actualTypeArgument instanceof TypeVariable) {
TypeVariable typeVariable = (TypeVariable) actualTypeArgument;
System.out.println("泛型类型参数的名字为 " + typeVariable.getName()); // 打印:T
Type[] bounds = typeVariable.getBounds();
for (Type bound : bounds) {
Class boundClass = (Class) bound;
System.out.println("泛型类型参数的上界为:" + boundClass.getName()); // 打印:java.lang.Number
}
}
打印信息:
泛型类型参数的名字为 T
泛型类型参数的上界为:java.lang.Number
判断 actualTypeArgument
这个 Type
对象是否是 TypeVariable
,通过判断;接着把 actualTypeArgument
强制类型转换为 TypeVariable
类型。
调用 TypeVariable
的两个函数:
String getName();
Type[] getBounds();
第一个函数是获取泛型类型参数的名字,这里获取到的是 T
,这和定义 Generator
时的类型参数是一样的;
第二个参数是获取泛型类型参数的上边界的 Type
数组。这里泛型类型参数 T
只有一个限定类型:Number
。
文档中的定义,GenericArrayType
表示一种数组类型,其组件类型为参数化类型或类型变量。
这句话告诉我们,组成 GenericArrayType
这个数组类型的元素要么是参数化类型ParameterizedType
,要么是类型变量 TypeVariable
。其他的类型如 Class
,WildcardType
,GenericArrayType
都不可以。
下面我们通过代码来演示。
首先,定义一个 ListArrayGenerator
普通接口,继承于 Generator
泛型接口,并且使用 List
这个实际类型替换了泛型类型参数:
public interface ListArrayGenerator extends Generator<List<Integer>[]>{
}
完整的测试代码如下:
public class _04_GenericArrayTypeTest {
public static void main(String[] args) {
Type[] types = ListArrayGenerator.class.getGenericInterfaces();
for (Type type : types) {
System.out.println("type = " + type); // Generator[]>
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
// 获取替换了泛型类型参数的实际类型的Type数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
if (actualTypeArgument instanceof GenericArrayType) {
GenericArrayType genericArrayType = (GenericArrayType) actualTypeArgument;
System.out.println("替换了泛型类型参数的实际类型为: " + genericArrayType);
Type genericComponentType = genericArrayType.getGenericComponentType();
System.out.println("泛型数组类型的元素类型为: " + genericComponentType);
}
}
}
}
}
}
打印结果如下:
type = com.java.advanced.features.reflect.genericsclass.blog.Generator[]>
替换了泛型类型参数的实际类型为: java.util.List[]
泛型数组类型的元素类型为: java.util.List
同样地,我们仍是一行一行地看上面的代码,这样可以更好地理解。
首先,看获取 ParameterizedType
的部分:
Type[] types = ListArrayGenerator.class.getGenericInterfaces();
for (Type type : types) {
System.out.println("type = " + type); // Generator[]>
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
ListArrayGenerator
继承的接口 Generator
是一个泛型接口,即参数化类型,对应的是 []>
ParameterizedType
,因此,type
可以通过 type instanceof ParameterizedType
的判断,进而把 type
强转为 ParameterizedType
类型。
其次,调用 getActualTypeArguments()
方法,获取替换了泛型类型参数的实际类型的 Type
对象数组:
// 获取替换了泛型类型参数的实际类型的Type数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
这里的 parameterizedType
,即 Generator
,替换了泛型类型参数的实际类型是 []>
List
,对应的是 ArrayGenericType
。
最后,看 GenericArrayType
部分:
if (actualTypeArgument instanceof GenericArrayType) {
GenericArrayType genericArrayType = (GenericArrayType) actualTypeArgument;
System.out.println("替换了泛型类型参数的实际类型为: " + genericArrayType);
Type genericComponentType = genericArrayType.getGenericComponentType();
System.out.println("泛型数组类型的元素类型为: " + genericComponentType);
}
打印信息:
替换了泛型类型参数的实际类型为: java.util.List[]
泛型数组类型的元素类型为: java.util.List
上面的 actualTypeArgument
,对应的是 GenericArrayType
,因此通过 actualTypeArgument instanceof GenericArrayType
判断,把 actualTypeArgument
强转为 GenericArrayType
类型。
调用 GenericArrayType
的函数:
Type getGenericComponentType();
这个函数的作用是获取泛型数组类型的元素类型。这里得到的是 List
类型。
进一步,我们可以验证这里的元素类型是 ParameterizedType
:
if (genericComponentType instanceof ParameterizedType) {
System.out.println("泛型数组类型的元素类型是ParameterizedType");
}
文档上的定义,WildcardType
表示一个通配符类型表达式,如 ?
、? extends Number
或 ? super Integer
。
定义一个 NumberListGenerator
接口,它继承于 Generator
接口,并且使用 List
来替换 Generator
泛型接口的类型参数 T
:
public interface NumberListGenerator extends Generator<List<? extends Number>>{
}
下面是完整的测试代码:
public class _05_WildcardTypeTest {
public static void main(String[] args) {
Type[] types = NumberListGenerator.class.getGenericInterfaces();
for (Type type : types) {
System.out.println("type = " + type); // Generator>
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
if (actualTypeArgument instanceof ParameterizedType) {
ParameterizedType typeArgument = (ParameterizedType) actualTypeArgument;
Type[] actualTypeArguments1 = typeArgument.getActualTypeArguments();
for (Type type1 : actualTypeArguments1) {
if (type1 instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) type1;
System.out.println("wildcardType = " + wildcardType);
Type[] lowerBounds = wildcardType.getLowerBounds();
for (Type lowerBound : lowerBounds) {
System.out.println("lowerBound = " + lowerBound);
}
Type[] upperBounds = wildcardType.getUpperBounds();
for (Type upperBound : upperBounds) {
System.out.println("upperBound = " + upperBound);
}
}
}
}
}
}
}
}
}
这段代码长得有点可以了。不过,我们仍然是一点点地看,一定会弄明白的。
首先,看获取 ParameterizedType
的部分:
Type[] types = NumberListGenerator.class.getGenericInterfaces();
for (Type type : types) {
System.out.println("type = " + type); // Generator>
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
NumberListGenerator
继承的接口 Generator
是一个泛型接口,即参数化类型,对应的是 >
ParameterizedType
,因此,type
可以通过 type instanceof ParameterizedType
的判断,进而把 type
强转为 ParameterizedType
类型。
其次,调用 getActualTypeArguments()
方法,获取替换了泛型类型参数的实际类型的 Type
对象数组:
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
这里的 parameterizedType
,即 Generator
,替换了泛型类型参数的实际类型是 >
List
,对应的是 ParameterizedType
。
接着,把上一步获取到的实际类型,通过类型转换为 ParameterizedType
:
for (Type actualTypeArgument : actualTypeArguments) {
if (actualTypeArgument instanceof ParameterizedType) {
ParameterizedType typeArgument = (ParameterizedType) actualTypeArgument;
这一步的 typeArgument
是一个 ParameterizedType
类型,对应的是 List
。
接着,既然 typeArgument
是一个 ParameteizedType
类型,我们可以调用 getActualTypeArguments()
方法获取替换了泛型类型参数的实际类型:
Type[] actualTypeArguments1 = typeArgument.getActualTypeArguments();
这里的 typeArgument
是一个 ParameterizedType
类型,对应的是 List
;通过调用 getActualTypeArguments()
方法,获取到的就是替换了List
泛型接口的类型参数 T
的实际类型,即 ? extends Number
。
接着,把上一步获取到的就是替换了List
泛型接口的类型参数 T
的实际类型类型转换为 WildcardType
类型:
for (Type type1 : actualTypeArguments1) {
if (type1 instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) type1;
最后,调用 WildcardType
的两个方法:
Type[] getUpperBounds();
Type[] getLowerBounds();
来获取上边界和下边界的信息。
代码如下:
Type[] lowerBounds = wildcardType.getLowerBounds();
for (Type lowerBound : lowerBounds) {
System.out.println("lowerBound = " + lowerBound);
}
Type[] upperBounds = wildcardType.getUpperBounds();
for (Type upperBound : upperBounds) {
System.out.println("upperBound = " + upperBound);
}
打印信息:
upperBound = class java.lang.Number
本文介绍了泛型类的周边信息获取,以及 Type
体系,希望能够帮助到大家。巩固好反射知识,对于阅读框架源码是很有帮助的。
文末的参考链接,大家也可以看一下,都是很不错的文章。