概述
Type是Java编程语言中所有类型的通用超级接口。 这些包括原始类型,参数化类型,数组类型,类型变量和基本类型。
具体实现
实现Type的具体类型一共有五种,分别是Class(原始类型)、ParameterizedType(参数化的类型、泛型类型)、TypeVariable(类型变量)、WildcardType(通配符类型)、GenericArrayType(数组类型)这五种java中的具体类型。

Class
1 2 3 4 5 6
| public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, AnnotatedElement { ...... }
|
java中每一个对象都有一个确定的Class,可以通过Object的getClass()方法或者类名.class
等方法获取这个Class,拿到这个Class对象后我们就可以通过反射获取对象的一些特殊属性了。例如获取对象的Constructor、Method、Field等等。Class是java反射的基础,相关的方法调用就不再赘述了 。
ParameterizedType
ParameterizedType表示参数化类型,例如List<String>、Map<String,String>
就是参数化的的类型,也就是我们平时说的泛型。
1 2 3 4 5 6 7 8 9 10 11
| public interface ParameterizedType extends Type {
Type[] getActualTypeArguments();
Type getRawType();
Type getOwnerType(); }
|
看一个具体的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| package com.zyc;
import java.lang.reflect.ParameterizedType; import java.util.Arrays; import java.util.List;
public class ParameterizedTypeTest<T> {
public static void main(String[] args) { class F<T> { } class E extends F<String> {
} print(ParameterizedTypeTest.B.class); print(ParameterizedTypeTest.C.class); print(D.class); print(E.class); }
private static void print(Class<?> clazz) { ParameterizedType type = (ParameterizedType) clazz.getGenericSuperclass(); String str = clazz.getName() + "[" + Arrays.toString(type.getActualTypeArguments()) + "," + type.getRawType() + "," + type.getOwnerType() + "]"; System.out.println(str);
}
static class A<T> {
}
static class B<T> extends ParameterizedTypeTest.A<T> {
}
static class C extends ParameterizedTypeTest.A<List<String>> {
} }
class D extends ParameterizedTypeTest<String> { }
|
控制台输出
1 2 3 4
| com.zyc.ParameterizedTypeTest$B[[T],class com.zyc.ParameterizedTypeTest$A,class com.zyc.ParameterizedTypeTest] com.zyc.ParameterizedTypeTest$C[[java.util.List<java.lang.String>],class com.zyc.ParameterizedTypeTest$A,class com.zyc.ParameterizedTypeTest] com.zyc.D[[class java.lang.String],class com.zyc.ParameterizedTypeTest,null] com.zyc.ParameterizedTypeTest$1E[[class java.lang.String],class com.zyc.ParameterizedTypeTest$1F,null]
|
在main方法中通过print方法分别打印B、C、D、E这四个类的ParameterizedType的父类,其中getActualTypeArguments方法明确的反映了父类在源码中的类型参数。getRawType方法则反映了ParameterizedType父类的实际类型。getOwnerType方法则反映了ParameterizedType父类所在类的类型,对于B、C来说它们的父类都是ParameterizedTypeTest$A,而ParameterizedTypeTest$A是被定义在ParameterizedTypeTest中的静态内部类,所以getOwnerType方法返回了com.zyc.ParameterizedTypeTest,而对于D、E来说它们的父类ParameterizedTypeTest和F都是单独定义的顶级类(非嵌套类)所以getOwnerType方法最终返回了null。
由于java类型擦除的原因,我们无法在运行时获取诸如T、O这种类型变量的实际类型,但是我们可以利用ParameterizedType的getActualTypeArguments方法定义一个TypeToken
,通过new一个匿名的子类然后反射获取被擦出对象的实际类型。实际上很多第三方库例如Gson、guava都是通过这种方式来获取泛型的实际类型的。
一个简单的TypeToken例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.zyc;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List;
public abstract class TypeToken<T> {
private final Type runtimeType;
public TypeToken() { Type superclass = getClass().getGenericSuperclass(); if (!(superclass instanceof ParameterizedType)) { throw new IllegalArgumentException(getClass() + "必须是参数化类型"); } runtimeType = ((ParameterizedType) superclass).getActualTypeArguments()[0]; } }
|
通过这个TypeToken我们就能够在运行时获取泛型类型的具体类型了
new TypeToken<List<String>>() {}.getType() => java.util.List<java.lang.String>
TypeVariable
TypeVariable意为类型变量,也就是ParameterizedType中的变量,也就是我们常见的T、O这些泛型参数,例如List<String>
中的String就是TypeVariable,而整个List<String>
则代表着ParameterizedType。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement { Type[] getBounds();
D getGenericDeclaration(); String getName(); AnnotatedType[] getAnnotatedBounds(); }
|
看一个具体的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package com.zyc;
import java.io.Serializable; import java.lang.reflect.TypeVariable; import java.util.Arrays;
public class TypeVariableTest<T extends Number & Cloneable & Serializable> {
<O> TypeVariableTest(O o) {
}
private static <T> void test(T t) {
}
public static void main(String[] args) throws Exception { print(TypeVariableTest.class.getTypeParameters()[0]);
print(TypeVariableTest.class.getDeclaredConstructors()[0].getTypeParameters()[0]);
print(TypeVariableTest.class.getDeclaredMethod("test", Object.class).getTypeParameters()[0]);
}
private static void print(TypeVariable typeVariable) { System.out.println(typeVariable.getGenericDeclaration() + "[" + typeVariable.getName() + "," + Arrays.toString(typeVariable.getBounds()) + "]" ); }
}
|
控制台输出:
1 2 3
| class com.zyc.TypeVariableTest[T,[class java.lang.Number, interface java.lang.Cloneable, interface java.io.Serializable]] com.zyc.TypeVariableTest(java.lang.Object)[O,[class java.lang.Object]] public static void com.zyc.TypeVariableTest.test(java.lang.Object)[T,[class java.lang.Object]]
|
从结果可以看出getName方法明确的反映了类型变量在定义在源码中的名称,getBounds方法反映了类型变量的按顺序定义的所有上边界,你可能会好奇为什么没有下边界,因为super关键字不能用在类型变量的定义上,只能用在通配符声明上。getGenericDeclaration方法则明确的反映了定义类型变量的对象。并且所有继承GenericDeclaration的对象都可以声明类型变量。

从上图的GenericDeclaration类图上我们可以看出Class和Executable都继承了它,而Constructor和Method继承了Executable,因此Class、Constructor、Method这三者都可以声明类型变量。
WildcardType
WildcardType表示通配符类型表达式,例如?
、? extends Number
、? super Integer
。
1 2 3 4 5 6 7 8
| public interface WildcardType extends Type { Type[] getUpperBounds();
Type[] getLowerBounds(); }
|
看一个具体的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| package com.zyc;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.WildcardType; import java.util.Arrays; import java.util.List;
public class WildcardTypeTest<T> {
public List<? extends Number> list1;
public List<? super Number> list2;
public List<? extends T> list3;
public static void main(String[] args) throws Exception { ParameterizedType list1 = (ParameterizedType) WildcardTypeTest.class.getField("list1").getGenericType(); ParameterizedType list2 = (ParameterizedType) WildcardTypeTest.class.getField("list2").getGenericType(); ParameterizedType list3 = (ParameterizedType) WildcardTypeTest.class.getField("list3").getGenericType(); print((WildcardType) list1.getActualTypeArguments()[0]); print((WildcardType) list2.getActualTypeArguments()[0]); print((WildcardType) list3.getActualTypeArguments()[0]); }
private static void print(WildcardType wildcardType) { System.out.println("UpperBounds:" + Arrays.toString(wildcardType.getUpperBounds()) + "," + "LowerBounds:" + Arrays.toString(wildcardType.getLowerBounds())); } }
|
控制台输出:
1 2 3
| UpperBounds:[class java.lang.Number],LowerBounds:[] UpperBounds:[class java.lang.Object],LowerBounds:[class java.lang.Number] UpperBounds:[T],LowerBounds:[]
|
main方法中通过反射将WildcardTypeTest类中的三个ParameterizedType的集合中的WildcardType的类型参数的上边界和下边界分别打印出来了。
GenericArrayType
GenericArrayType表示那些组件类型为ParameterizedType或TypeVariable的数组。(泛型数组)
1 2 3 4 5
| public interface GenericArrayType extends Type { Type getGenericComponentType(); }
|
看一个具体的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
package com.zyc;
import java.lang.reflect.GenericArrayType; import java.util.List;
public class GenericArrayTypeTest<T> {
public T[] array1;
public T[][] array2;
public List<String>[] array3;
public List<?>[] array4;
public static void main(String[] args) throws Exception { GenericArrayType array1 = (GenericArrayType) GenericArrayTypeTest.class.getDeclaredField("array1").getGenericType(); GenericArrayType array2 = (GenericArrayType) GenericArrayTypeTest.class.getDeclaredField("array2").getGenericType(); GenericArrayType array3 = (GenericArrayType) GenericArrayTypeTest.class.getDeclaredField("array3").getGenericType(); GenericArrayType array4 = (GenericArrayType) GenericArrayTypeTest.class.getDeclaredField("array4").getGenericType(); print(array1); print(array2); print(array3); print(array4); }
private static void print(GenericArrayType genericArrayType) { System.out.println(genericArrayType.getGenericComponentType().getClass()); } }
|
控制台输出:
1 2 3 4
| class sun.reflect.generics.reflectiveObjects.TypeVariableImpl class sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
|
main方法中通过反射将GenericArrayTypeTest类中的四个GenericArrayType的字段的内部元素类型输出到控制台,可以发现getGenericComponentType方法明确的反映了元素的Type。这里有一点需要注意的是如果数组内部的元素既不是ParameterizedType也不是TypeVariable,那么该数组代表的Type则是一个数组Class,而不是GenericArrayType。
总结
Type作为Java编程语言中所有类型的通用超级接口,涵盖Class(原始类型)、ParameterizedType(参数化的类型、泛型类型)、TypeVariable(类型变量)、WildcardType(通配符类型)、GenericArrayType(数组类型),以Class为切入点将所有的类型串联起来了,方便我们通过反射在运行时解析复杂的数据类型。