1 Type接口
Java中,JVM会为每一个加载到内存中的类型创建一个Class
对象。通过Class
对象我们可以获取Field
、Constructor
、Method
、Parameter
、Modifier
等几乎所有的类的元数据信息,这就是Java中反射的基础,为Java开发提供了很大的灵活性和通用性,是Java语言的一大亮点。
但是遇到泛型类(Generic Class)时,Class
就不灵光了。在类型擦除(Type erase)后,Class
丢失了泛型类型信息。比如,List<Integer>
和List<String>
这两个类型,他们的Class
对象是同一个,但是这两个类型又截然不同,这两个类型的变量不能相互赋值,也不能把一个List
中的元素存入另一个List
。
其实从Java 1.5开始,Java提供了一个Type
接口。Type
接口是所有类型的公共父接口,包括类和接口(raw types)、参数化类型(parameterized types)、数组类型(array types)、类型变量(type variables)和基本类型(primitive types),可以说,Type
是Java语言中的顶级类型接口。Class
就实现了Type
接口,List<Integer>
和List<String>
两个类型的Type
信息是不一样的。
有了Type类型,Java开发可以更加灵活,可以写出更加通用的代码。
我们先看看Type
接口的定义,它只有一个方法,就是获取Type
的字符串名字。
public interface Type {
default String getTypeName() {
return toString();
}
}
下面这些类和接口实现或扩展了Type
接口:
graph BT
B[Class]-->type[Type]
C[ParameterizedType]-->type
D[TypeVariable]-->type
E[GenericArrayType]-->type
F[WildcardType]-->type
从上图可以看到,除了Class
实现了Type
接口,还有四个接口(ParameterizedType、TypeVariable、GenericArrayType、WildcardType)扩展了Type
接口。
1.1 Class类
这个大家已经比较熟了,就不多介绍了。它的getTypeName()
返回的内容就是Class
的全限定域名(fully qualified domain name,FQDN)
1.2 ParameterizedType接口
ParameterizedType接口,跟它的名字一样,参数化类型,表示该类型带有类型参数,比如List<String>
这种。它的定义如下:
public interface ParameterizedType extends Type {
Type[] getActualTypeArguments();
Type getRawType();
Type getOwnerType();
}
getActualTypeArguments()
方法返回实际的参数类型,因为一个类型可以有多个类型参数,所以是一个数组。比如List<String>
类型的这个方法返回的是String
类的Class
对象(还记得Class
实现了Type
接口吗?)
getRawType()
方法返回擦除类型参数后的类型,比如List<String>
类型的这个方法返回的是List
类的Class
对象
getOwnerType()
方法,如果当前类型定义在另一个类型的内部,则返回外部的类型;否则,则是一个顶层类型(top-level type),返回null。比如List<String>
类型的这个方法返回的是null,但是Map.Entry<String, String>
类型的这个方法返回的就是Map
类的Class
对象,因为Entry
类定义在Map
类的内部
ParameterizedType
接口可能是我们使用的最多的Type
子接口,毕竟我们使用Type
类型,往往是希望知道类型的泛型参数的具体化后的类型。当然ParameterizedType
的泛型参数不一定具体化了,它只是表明这个类型包含类型参数。泛型参数是否具体化,可以通过getActualTypeArguments()
方法返回的Type
类型是Class
类型还是其他Type
类型来确定。不过这里还存在一个嵌套的问题,比如List<List<String>>
,它的ActualTypeArgument
是List<String>
,还是一个ParameterizedType
1.3 TypeVariable接口
跟它的名字一样,表示这是一个类型变量。比如类型List<T>
中的T
就是一个TypeVariable
。它的定义如下:
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
Type[] getBounds();
D getGenericDeclaration();
String getName();
AnnotatedType[] getAnnotatedBounds();
}
通过TypeVariable
我们主要通过getBounds()
和getName()
方法获取它的边界和名字。比如List<T extends Person>
类型,它的ActualTypeArgument
是TypeVariable
类型,这个TypeVariable
的名字是T
,边界是Person
Class
类型。
1.4 GenericArrayType接口
泛型数组类型接口,它的定义如下:
public interface GenericArrayType extends Type {
Type getGenericComponentType();
}
GenericArrayType
接口只有一个getGenericComponentType()
方法,返回数组元素的类型,如List<String>[]
类型返回的结果是List<String>
类型,他是一个ParameterizedType
1.5 WildcardType接口
表示泛型的通配符(?)类型,比如List<?>
中的?
。它的定义如下:
public interface WildcardType extends Type {
Type[] getUpperBounds();
Type[] getLowerBounds();
}
WildcardType
接口提供了两个接口,分别获取通配符?
的上下边界。比如List<? extends Person>
的上边界是Person
Class
。List<? super Person>
的下边界是Person
Class
。
2 获取Type接口信息
我们可以通过类的全限定域名或类的对象获取Class
对象,Type
则可以通过Class
、Field
、Method
、Constructor
、Parameter
这些表示类的元数据对象获取,因为Field
、Method
、Constructor
、Parameter
只能通过Class
间接获取,所以Type
信息都是从Class
获取的。
上述对象获取Class
信息的接口,接口名前带有generic
前缀的往往就是获取相应Type
信息的接口
下面通过一些实例观察获取Type
的一些接口信息,递归打印Type
信息的方法:
public static void printTypeInfo(final Type type) {
log.info("type.getTypeName(): {}", type.getTypeName());
if (type instanceof Class) {
Class c = (Class) type;
log.info("type is Class");
} else if (type instanceof ParameterizedType) {
ParameterizedType t = (ParameterizedType) type;
log.info("type is ParameterizedType");
Type[] actualTypeArguments = t.getActualTypeArguments();
log.info("ParameterizedType.getActualTypeArguments(): {}", Arrays.toString(actualTypeArguments));
for (int i = 0; i < actualTypeArguments.length; i++) {
printTypeInfo(actualTypeArguments[i]);
}
Type rawType = t.getRawType();
log.info("ParameterizedType.getRawType(): {}", rawType);
printTypeInfo(rawType);
Type ownerType = t.getOwnerType();
log.info("ParameterizedType.getOwnerType(): {}", ownerType);
if (ownerType != null) {
printTypeInfo(ownerType);
}
} else if (type instanceof TypeVariable) {
TypeVariable t = (TypeVariable) type;
log.info("type is TypeVariable");
String name = t.getName();
log.info("TypeVariable.getName(): {}", name);
Type[] bounds = t.getBounds();
log.info("TypeVariable.getBounds(): {}", Arrays.toString(bounds));
if (bounds != null) {
for (int i = 0; i < bounds.length; i++) {
printTypeInfo(bounds[i]);
}
}
} else if (type instanceof GenericArrayType) {
GenericArrayType t = (GenericArrayType) type;
log.info("type is GenericArrayType");
Type componentType = t.getGenericComponentType();
log.info("GenericArrayType.getGenericComponentType(): {}", componentType);
printTypeInfo(componentType);
} else if (type instanceof WildcardType) {
WildcardType t = (WildcardType) type;
log.info("type is WildcardType");
Type[] upperBounds = t.getUpperBounds();
log.info("WildcardType.getUpperBounds(): {}", Arrays.toString(upperBounds));
if (upperBounds != null) {
for (int i = 0; i < upperBounds.length; i++) {
printTypeInfo(upperBounds[i]);
}
}
Type[] lowerBounds = t.getLowerBounds();
log.info("WildcardType.getLowerBounds(): {}", Arrays.toString(lowerBounds));
if (lowerBounds != null) {
for (int i = 0; i < lowerBounds.length; i++) {
printTypeInfo(lowerBounds[i]);
}
}
}
}
2.1 Class
用来测试的类:
public interface Interface1 {
}
public interface Interface2<T1, T2> {
}
public class Class2<T> {
}
public class Class1<T, S> extends Class2<S> implements Interface1, Interface2<String, T> {
}
2.1.1 获取父类的Type
: getGenericSuperclass()
测试代码:
Class c = Class1.class;
Type genericSuperclass = c.getGenericSuperclass();
log.info("=====begin print genericSuperclass");
if (genericSuperclass != null) {
printTypeInfo(genericSuperclass);
}
log.info("=====finish print genericSuperclass");
打印结果:
=====begin print genericSuperclass
type.getTypeName(): com.javatest.generic.Class2<S>
type is ParameterizedType
ParameterizedType.getActualTypeArguments(): [S]
type.getTypeName(): S
type is TypeVariable
TypeVariable.getName(): S
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
ParameterizedType.getRawType(): class com.javatest.generic.Class2
type.getTypeName(): com.javatest.generic.Class2
type is Class
ParameterizedType.getOwnerType(): null
=====finish print genericSuperclass
2.1.2 获取父接口的Type
: getGenericInterfaces()
测试代码:
Type[] genericSuperInterfaces = c.getGenericInterfaces();
log.info("=====begin print genericSuperInterfaces");
if (genericSuperInterfaces != null) {
for (int i = 0; i < genericSuperInterfaces.length; i++) {
log.info("=====begin print genericSuperInterfaces, i={}", i);
printTypeInfo(genericSuperInterfaces[i]);
log.info("=====finish print genericSuperInterfaces i={}", i);
}
}
log.info("=====finish print genericSuperInterfaces");
打印结果:
=====begin print genericSuperInterfaces
=====begin print genericSuperInterfaces, i=0
type.getTypeName(): com.javatest.generic.Interface1
type is Class
=====finish print genericSuperInterfaces i=0
=====begin print genericSuperInterfaces, i=1
type.getTypeName(): com.javatest.generic.Interface2<java.lang.String, T>
type is ParameterizedType
ParameterizedType.getActualTypeArguments(): [class java.lang.String, T]
type.getTypeName(): java.lang.String
type is Class
type.getTypeName(): T
type is TypeVariable
TypeVariable.getName(): T
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
ParameterizedType.getRawType(): interface com.javatest.generic.Interface2
type.getTypeName(): com.javatest.generic.Interface2
type is Class
ParameterizedType.getOwnerType(): null
=====finish print genericSuperInterfaces i=1
=====finish print genericSuperInterfaces
2.1.3 获取类型参数的Type
: getTypeParameters()
测试代码:
TypeVariable[] typeVariables = c.getTypeParameters();
log.info("=====begin print typeVariables");
if (typeVariables != null) {
for (int i = 0; i < typeVariables.length; i++) {
log.info("=====begin print typeVariables, i={}", i);
printTypeInfo(typeVariables[i]);
log.info("=====finish print typeVariables i={}", i);
}
}
log.info("=====finish print typeVariables");
打印结果:
=====begin print typeVariables
=====begin print typeVariables, i=0
type.getTypeName(): T
type is TypeVariable
TypeVariable.getName(): T
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
=====finish print typeVariables i=0
=====begin print typeVariables, i=1
type.getTypeName(): S
type is TypeVariable
TypeVariable.getName(): S
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
=====finish print typeVariables i=1
=====finish print typeVariables
2.2 Field
用来测试的类
public class Class2<T> {
String str;
List<String> strList1;
List<T> strList2;
T t1;
}
2.2.1 类属性的Type
: getGenericType()
测试代码:
Class c = Class2.class;
log.info("=====begin pring field str");
Field f = c.getDeclaredField("str");
Type type = f.getGenericType();
printTypeInfo(type);
log.info("=====finish pring field str");
log.info("=====begin pring field strList1");
f = c.getDeclaredField("strList1");
type = f.getGenericType();
printTypeInfo(type);
log.info("=====finish pring field strList1");
log.info("=====begin pring field strList2");
f = c.getDeclaredField("strList2");
type = f.getGenericType();
printTypeInfo(type);
log.info("=====finish pring field strList2");
log.info("=====begin pring field t1");
f = c.getDeclaredField("t1");
type = f.getGenericType();
printTypeInfo(type);
log.info("=====finish pring field t1");
打印结果:
=====begin pring field str
type.getTypeName(): java.lang.String
type is Class
=====finish pring field str
=====begin pring field strList1
type.getTypeName(): java.util.List<java.lang.String>
type is ParameterizedType
ParameterizedType.getActualTypeArguments(): [class java.lang.String]
type.getTypeName(): java.lang.String
type is Class
ParameterizedType.getRawType(): interface java.util.List
type.getTypeName(): java.util.List
type is Class
ParameterizedType.getOwnerType(): null
=====finish pring field strList1
=====begin pring field strList2
type.getTypeName(): java.util.List<T>
type is ParameterizedType
ParameterizedType.getActualTypeArguments(): [T]
type.getTypeName(): T
type is TypeVariable
TypeVariable.getName(): T
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
ParameterizedType.getRawType(): interface java.util.List
type.getTypeName(): java.util.List
type is Class
ParameterizedType.getOwnerType(): null
=====finish pring field strList2
=====begin pring field t1
type.getTypeName(): T
type is TypeVariable
TypeVariable.getName(): T
TypeVariable.getBounds(): [class java.lang.Object]
type.getTypeName(): java.lang.Object
type is Class
=====finish pring field t1
2.3 Method
从上面Class
和Field
的例子应该知道怎么回事了,后面不再给出例子,只给出获取Type
信息的方法