一、Type接口
Type是所有类型的父接口,他有4个子接口和一个实现类。
- Class比较常见,它表示的是原始类型。Class类的对象表示JVM中的一个类或接口。每个Java类在JVM里都表现为一个Class对象,可以通过“类名.class”、“对象.getClass()”、“Class.forName(“类名”)”等方式获取Class对象。数组也被映射为Class对象,所有元素类型相同且维数相同的数组都共享同一个Class对象。
- ParameterizedType表示的是参数化类型,例如List<String>、Map<Integer,String>、Service<User>这种带有泛型的类型。
ParameterizedType接口中常用的方法有3个,分别是:
(1) Type getRawType()——返回参数化类型中的原始类型,例如List<String>的原始类型为List。
(2) Type[] getActualTypeArguments()——获取参数化类型的类型变量或是实际类型列表,例如Map<Integer,String>的实际泛型列表是Integer和String。需要注意的是,该列表的元素类型是Type,也就是说,可能存在多重嵌套的情况。
(3) Type getOwerType()——返回的是类型所属的类型,例如存在A<T>,其中定义了内部类InnerA<T>,则InnerA<T>所属的类型是A<T>,如果是顶层类型则返回null。这种关系常见与Map<K,V>接口与Map.Entry<K,V>接口,Map<K,V>是Map.Entry<K,V>接口的所有者。 - TypeVariable表示的是类型变量,它用来反映的是JVM编译该泛型前的信息,例如List<T>中的T就是类型变量,它在编译时需要被转换为一个具体的类型后才能正常使用。
该接口常用的方法有3个,分别是:
(1) Type[] getBounds()——获取类型变量的上边界,如果未明确声明上边界则默认为Object。例如Class<K extents Person>中K的上边界就是Person。
(2) D getGenericDeclaration()——获取声明该类型变量的原始类型,例如Test<K extents Person>中原始类型是Test。
(3) String getName()——获取在源码中定义的名字,上例中为K。 - GenericArrayType表示的是数组类型且组成元素时ParameterizedType或TypeVariable,例如List<T>或T[],该接口只有Type getGenericComponentType()一个方法,它返回数组的组成元素类型。
- WildcardType表示的通配符类型,例如? extends Number 和 ? super Integer。
Wildcard接口有两个方法,分别是:
(1) Type[] getUpperBounds()——返回类型变量的上边界。
(2) Type[] getLowerBounds()——返回类型变量的下边界。
二、ParameterizedType与TypeVariable的使用
1.未指定泛型参数的泛型类(例如:ArrayList<T>)
public class TypeTest {
public static void main(String[] args) {
System.out.println("接口是否是泛型类:"+ (ArrayList.class.getGenericInterfaces()[0] instanceof ParameterizedType));
System.out.println("泛型类的名称:"+ ArrayList.class.getGenericInterfaces()[0].getTypeName());
System.out.println("泛型类的实现:"+ ArrayList.class.getGenericInterfaces()[0].getClass());
System.out.println("是否是泛型参数:"+(((ParameterizedType)ArrayList.class.getGenericInterfaces()[0]).getActualTypeArguments()[0] instanceof TypeVariable));
System.out.println("泛型参数名称:"+((ParameterizedType)ArrayList.class.getGenericInterfaces()[0]).getActualTypeArguments()[0].getTypeName());
System.out.println("泛型参数的实现:"+((ParameterizedType)ArrayList.class.getGenericInterfaces()[0]).getActualTypeArguments()[0].getClass());
}
}
//输出结果:
接口是否是泛型类:true
泛型类的名称:java.util.List<E>
泛型类的实现:class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
是否是泛型参数:true
泛型参数名称:E
泛型参数的实现:class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
在这里,我们使用的是ArrayList.class
,如果使用new ArrayList<String>().getClass()
,是否得到的泛型参数就是String呢?答案是否定的,因为this.getClass() 对象是被所有的不同具体类型的ArrayList实例 共享的(例如:new ArrayList<String>(), new ArrayList<Integer>()
等),所以在字节码中类型会被擦除到上限。
2.指定泛型参数的泛型类(例如:GenericSubClass<String>)
public class GenericClass<T> {
}
public class GenericSubClass1<String> extends GenericClass<String> {
}
public class GenericSubClass2 extends GenericClass<String> {
}
public class TypeTest {
public static void main(String[] args) {
Class clazz = GenericSubClass1.class;
//Class clazz = GenericSubClass2 .class;
//Class clazz = new GenericSubClass1().getClass();
//Class clazz = new GenericSubClass2().getClass();
System.out.println("父类是否是泛型类:"+ (clazz.getGenericSuperclass() instanceof ParameterizedType));
System.out.println("泛型类的名称:"+ clazz.getGenericSuperclass().getTypeName());
System.out.println("泛型类的实现:"+ clazz.getGenericSuperclass().getClass());
System.out.println("是否是泛型参数:"+(((ParameterizedType)clazz.getGenericSuperclass()).getActualTypeArguments()[0] instanceof TypeVariable));
System.out.println("泛型参数名称:"+((ParameterizedType)clazz.getGenericSuperclass()).getActualTypeArguments()[0].getTypeName());
System.out.println("泛型参数的实现:"+((ParameterizedType)clazz.getGenericSuperclass()).getActualTypeArguments()[0].getClass());
}
}
//输出结果:
父类是否是泛型类:true
泛型类的名称:com.arch.test.reflect.GenericClass<String>
泛型类的实现:class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
是否是泛型参数:true
泛型参数名称:String
泛型参数的实现:class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
不管是使用"类.class"
,还是使用"对象.getClass()"
,得到的父类的泛型参数始终是String。