相关文章:
目录
1. 前言
本文主要介绍获取泛型超类和泛型接口的相关信息;Type 的分类以及在泛型超类和泛型接口中的使用案例。
这部分内容不是很好理解,需要好好消化消化。这部分内容算是反射里比较难懂的部分,有必要好好学习掌握,这样才能在阅读源码时更加顺畅。
2. 正文
2.1 获取泛型超类和泛型接口的相关信息
2.1.1 获取泛型超类的相关信息
在上篇文章 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<java.lang.Integer>
可以看到,通过 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>
替换泛型类型参数的实际类型为:java.lang.Integer
声明了泛型类型的原始类型为:com.java.advanced.features.reflect.genericsclass.blog.Holder
可以看到,代码中通过了 type instanceof ParameterizedType 判断,说明 type 是 ParameterizedType 的一个实例,再看一下 type 的打印是 Holder<Integer>,它是一个泛型类型,对应的是 ParameterizedType。
然后,我们通过调用 ParameterizedType 的两个方法:
Type[] getActualTypeArguments();
Type getRawType();
第一个方法是获取替换了泛型类型参数的实际类型的 Type对象的数组。这个方法里,我们需要注意的是,返回的是一个数组,而且数组的元素也是 Type 类型的。
这是为什么呢?返回一个数组是因为泛型类型参数可以有多个,就像一个方法可以声明多个形式参数一样。数组的元素类型是 Type,这是因为不仅仅是 Class 用于替换类型参数,其他的 Type 子接口也可以。
第二个方法是获取声明了泛型类型的原始类型。需要注意的一点是“原始类型"的概念一定是和泛型类型在一起的。如果不是泛型类型,那么就无所谓原始类型。
2.1.2 获取泛型接口的相关信息
在上篇文章 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<java.lang.Integer>
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<java.lang.Integer>
替换泛型类型参数的实际类型为: class java.lang.Integer
声明了泛型接口的原始类型为: interface com.java.advanced.features.reflect.genericsclass.blog.Generator
type = interface java.io.Serializable
2.2 Type
在 2.1 中,演示了 ParameterizedType 和 Class 的使用,本节会演示 TypeVariable,GenericArrayType 和 WildcardType 的使用。
2.2.1 ParameterizedType
ParameterizedType 表示参数化类型,如 Collection<String>。
2.2.2 TypeVariable
文档上的定义是,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<T>
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>
泛型类型参数的名字为 T
泛型类型参数的上界为:java.lang.Number
上面的测试代码看着可能觉得有点多,我们一点一点来看,肯定能够全部理解的。
首先,看获取 ParameterizedType 的部分:
// 获取此接口直接继承的接口对应的 Type 对象数组
Type[] types = NumberGenerator.class.getGenericInterfaces();
for (Type type : types) {
System.out.println("type = " + type); // 打印:Generator<T>
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
大家不要去想 for-each 循环,我们这里 types 数组的长度就是 1,因为 NumberGenerator 直接继承的接口只有一个,就是 Generator。
看一下这里获取到的 type 的值:
type = com.java.advanced.features.reflect.genericsclass.blog.Generator<T>
Generator<T> 说明 type 是一个泛型类型,即参数化类型,对应的是 ParameterizedType。因此,可以通过 type instanceof ParameterizedType 的条件判断,进而把 type 强制类型转换为 ParameterizedType 类型。
接着,调用 getActualTypeArguments() 方法,获取替换了泛型类型参数的实际类型的 Type 对象数组:
// 获取替换了泛型类型参数的实际类型的 Type 对象数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
我们这里 parameterizedType,即对应 Generator<T>。其实,这里并没有使用实际类型替换泛型类型参数,只是传入了一个类型参数而已。
因为 Generator<T> 只有一个类型参数,所以 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<T> 时的类型参数是一样的;
第二个参数是获取泛型类型参数的上边界的 Type 数组。这里泛型类型参数 T 只有一个限定类型:Number。
2.2.3 GenericArrayType
文档中的定义,GenericArrayType 表示一种数组类型,其组件类型为参数化类型或类型变量。
这句话告诉我们,组成 GenericArrayType 这个数组类型的元素要么是参数化类型ParameterizedType,要么是类型变量 TypeVariable。其他的类型如 Class,WildcardType,GenericArrayType 都不可以。
下面我们通过代码来演示。
首先,定义一个 ListArrayGenerator 普通接口,继承于 Generator 泛型接口,并且使用 List<Integer>[] 这个实际类型替换了泛型类型参数:
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<List<Integer>[]>
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.lang.Integer>[]>
替换了泛型类型参数的实际类型为: java.util.List<java.lang.Integer>[]
泛型数组类型的元素类型为: java.util.List<java.lang.Integer>
同样地,我们仍是一行一行地看上面的代码,这样可以更好地理解。
首先,看获取 ParameterizedType 的部分:
Type[] types = ListArrayGenerator.class.getGenericInterfaces();
for (Type type : types) {
System.out.println("type = " + type); // Generator<List<Integer>[]>
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
ListArrayGenerator 继承的接口 Generator<List<Integer>[]> 是一个泛型接口,即参数化类型,对应的是 ParameterizedType,因此,type 可以通过 type instanceof ParameterizedType 的判断,进而把 type 强转为 ParameterizedType 类型。
其次,调用 getActualTypeArguments() 方法,获取替换了泛型类型参数的实际类型的 Type 对象数组:
// 获取替换了泛型类型参数的实际类型的Type数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
这里的 parameterizedType,即 Generator<List<Integer>[]>,替换了泛型类型参数的实际类型是 List<Integer>[],对应的是 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.lang.Integer>[]
泛型数组类型的元素类型为: java.util.List<java.lang.Integer>
上面的 actualTypeArgument,对应的是 GenericArrayType,因此通过 actualTypeArgument instanceof GenericArrayType 判断,把 actualTypeArgument 强转为 GenericArrayType 类型。
调用 GenericArrayType 的函数:
Type getGenericComponentType();
这个函数的作用是获取泛型数组类型的元素类型。这里得到的是 List<Integer>类型。
进一步,我们可以验证这里的元素类型是 ParameterizedType:
if (genericComponentType instanceof ParameterizedType) {
System.out.println("泛型数组类型的元素类型是ParameterizedType");
}
2.2.4 WildcardType
文档上的定义,WildcardType 表示一个通配符类型表达式,如 ?、? extends Number 或 ? super Integer。
定义一个 NumberListGenerator 接口,它继承于 Generator 接口,并且使用 List<? extends Number> 来替换 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<List<? extends Number>>
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<List<? extends Number>>
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
NumberListGenerator 继承的接口 Generator<List<? extends Number>> 是一个泛型接口,即参数化类型,对应的是 ParameterizedType,因此,type 可以通过 type instanceof ParameterizedType 的判断,进而把 type 强转为 ParameterizedType 类型。
其次,调用 getActualTypeArguments() 方法,获取替换了泛型类型参数的实际类型的 Type 对象数组:
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
这里的 parameterizedType,即 Generator<List<? extends Number>>,替换了泛型类型参数的实际类型是 List<? extends Number>,对应的是 ParameterizedType。
接着,把上一步获取到的实际类型,通过类型转换为 ParameterizedType:
for (Type actualTypeArgument : actualTypeArguments) {
if (actualTypeArgument instanceof ParameterizedType) {
ParameterizedType typeArgument = (ParameterizedType) actualTypeArgument;
这一步的 typeArgument 是一个 ParameterizedType 类型,对应的是 List<? extends Number>。
接着,既然 typeArgument 是一个 ParameteizedType 类型,我们可以调用 getActualTypeArguments() 方法获取替换了泛型类型参数的实际类型:
Type[] actualTypeArguments1 = typeArgument.getActualTypeArguments();
这里的 typeArgument 是一个 ParameterizedType 类型,对应的是 List<? extends Number>;通过调用 getActualTypeArguments() 方法,获取到的就是替换了List<T> 泛型接口的类型参数 T 的实际类型,即 ? extends Number。
接着,把上一步获取到的就是替换了List<T> 泛型接口的类型参数 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
3. 最后
本文介绍了泛型类的周边信息获取,以及 Type 体系,希望能够帮助到大家。巩固好反射知识,对于阅读框架源码是很有帮助的。
文末的参考链接,大家也可以看一下,都是很不错的文章。
本文详细介绍了Java中泛型类的周边信息获取方法,包括泛型超类、泛型接口及相关信息的获取,同时深入探讨了Type体系,如ParameterizedType、TypeVariable、GenericArrayType和WildcardType的使用,有助于读者深入理解Java反射机制。
:泛型周边信息获取&spm=1001.2101.3001.5002&articleId=106584902&d=1&t=3&u=595fbb57a4074980b7f62e3769ce0fbc)
2万+

被折叠的 条评论
为什么被折叠?



