Type直接子接口java
全部类型都是Type类型子类数组
表示参数化类型。好比:Map这种参数化类型 获取参数化类型<>中的实际类型 源码声明:Type[] getActualTypeArguments(); 【注意】不管<>中有几层<>嵌套,这个方法仅仅脱去最外层的<>以后剩下的内容就做为这个方法的返回值。安全
ArrayList> al1 经过getActualTypeArguments()返回以后,脱去最外层的<>以后,剩余的类型是ArrayList。所以对这个参数的返回类型是ParameterizedType。spa
ArrayList al2 经过getActualTypeArguments()返回以后,脱去最外层的<>以后,剩余的类型是E。所以对这个参数的返回类型是TypeVariable。code
ArrayList al3 经过getActualTypeArguments()返回以后,脱去最外层的<>以后,剩余的类型是String。所以对这个参数的返回类型是Class。对象
ArrayList al4 经过getActualTypeArguments()返回以后,脱去最外层的<>以后,剩余的类型是? ExtendsNumber。所以对这个参数的返回类型是WildcardType。接口
ArrayList al5(){} 经过getActualTypeArguments()返回以后,脱去最外层的<>以后,剩余的类型是E[]。所以对这个参数的返回类型是GenericArrayType。element
因此,可能得到各类各样类型的实际参数,因此为了统一,采用直接父类数组Type[]进行接收。开发
方法:get
Type getRawType(): 返回承载该泛型信息的对象, 如上面那个Map<String, String>承载范型信息的对象是Map
Type[] getActualTypeArguments(): 返回实际泛型类型列表, 如上面那个Map<String, String>实际范型列表中有两个元素, 都是String,
getActualTypeArguments返回的有多是ParameterizedType,GenericArrayType,TypeVariable, WildCardType。
import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; /** * @author yeweigen */ public class Test { static class SuperClass<T>{} static class ParameterizedTypeCase<T> extends SuperClass<SuperClass<T>> {} static class TypeVariableCase<T> extends SuperClass<T> {} static class GenericArrayTypeCase<T> extends SuperClass<T[]> {} static class GenericArrayTypeCase1 extends SuperClass<String[]> {} public static void main(String [] args) { printActualTypeArguments(getParameterizedType(ParameterizedTypeCase.class)); printActualTypeArguments(getParameterizedType(TypeVariableCase.class)); printActualTypeArguments(getParameterizedType(GenericArrayTypeCase.class)); printActualTypeArguments(getParameterizedType(GenericArrayTypeCase1.class)); } public static ParameterizedType getParameterizedType(Class clazz) { Type type = clazz.getGenericSuperclass(); if (type instanceof ParameterizedType) { return (ParameterizedType) type; } return null; } public static void printActualTypeArguments(ParameterizedType type) { if (type == null ) return; Type[] types = type.getActualTypeArguments(); if (types[0] instanceof ParameterizedType) { System.out.println("First element of "+ type + " getActualTypeArguments() is instanceof ParameterizedType"); } if (types[0] instanceof TypeVariable) { System.out.println("First element of "+ type + " getActualTypeArguments() is instanceof TypeVariable"); } if (types[0] instanceof GenericArrayType) { System.out.println("First element of "+ type + " getActualTypeArguments() is instanceof GenericArrayType"); } if (types[0] instanceof Class) { System.out.println("First element of "+ type + " getActualTypeArguments() is instanceof Class"); } } }
Type getOwnerType(): 返回是谁的member.(上面那两个最经常使用)
表示泛型数组类型。好比:void method(ArrayList[] al){…} 【注意】<>不能出如今数组的初始化中,即new数组以后不能出现<>,不然javac没法经过。可是做为引用变量或者方法的某个参数是彻底能够的。 获取泛型数组中元素的类型 源码声明:Type getGenericComponentType(); 【注意】不管从左向右有几个[]并列,这个方法仅仅脱去最右边的[]以后剩下的内容就做为这个方法的返回值。为何返回值类型是Type?
String[] p1 经过getComponentType()返回以后,脱去最右边的[]以后,剩余的类型是String。所以对这个参数的返回类型是Class。
*E[] p2 经过getComponentType()返回以后,脱去最右边的[]以后,剩余的类型是E。所以对这个参数的返回类型是TypeVariable。
ArrayList[] p3 经过getComponentType()返回以后,脱去最右边的[]以后,剩余的类型是ArrayList。所以对这个参数的返回类型是ParameterizedType。
E[][] p4(){} 经过getComponentType()返回以后,脱去最右边的[]以后,剩余的类型是E[]。所以对这个参数的返回类型是GenericArrayType。
TypeVariable 接口类型的含义
表示类型参数或者又叫作类型变量。好比:void method(E e){}中的E就是类型变量 获取类型变量的泛型限定的上边界的类型 源码声明:Type[] getActualTypeArguments();
【注意】这里面仅仅是上边界。缘由就是类型变量在定义的时候只能使用extends进行(多)边界限定。不能使用super,不然编译没法经过。同时extends给出的都是类型变量的上边界。
为何是返回类型是数组?由于类型变量能够经过&进行多个上边界限定,所以上边界有多个,所以返回值类型是数组类型[ ]。
例以下面的方法: public static & Cloneable&Serializable> E methodVI(E e){…} E的第一个上边界是Map,是ParameterizedType类型 E的第二个上边界是Cloneable,是Class类型 所以,为统一,返回值的数组的元素类型就是Type
表示通配符类型的表达式。 好比 void printColl(ArrayListal); 中的 ? extends Number
【注意】根据上面API的注释提示:现阶段通配符表达式仅仅接受一个上边界或者下边界,这个和定义类型变量时候能够指定多个上边界是不同。可是API说了,为了保持扩展性,这里返回值类型写成了数组形式。实际上如今返回的数组的大小就是1。
获取通配符表达式对象的泛型限定的上边界的类 源码声明:Type[] getUpperBounds(); 【注意】上面说了,现阶段返回的Type[ ]中的数组大小就是1个。写成Type[ ]是为了语言的升级而进行的扩展。
public static voidprintColl(ArrayList> al){}
通配符表达式是:? extendsArrayList,这样 extends后面是?的上边界,这个上边界是ParameterizedType类型。
public static voidprintColl(ArrayList al){}
通配符表达式是:? extends E,这样 extends后面是?的上边界,这个上边界是TypeVariable类型
public static voidprintColl(ArrayList al){}
通配符表达式是:? extends E[],这样 extends后面是?的上边界,这个上边界是GenericArrayType类型
public static voidprintColl(ArrayList al){}
通配符表达式是:? extends Number,这样 extends后面是?的上边界,这个上边界是Class类型 最终统一成Type做为数组的元素类型。
一. 泛型出现以前的类型
没有泛型的时候,只有所谓的原始类型。此时,全部的原始类型都经过字节码文件类Class类进行抽象。Class类的一个具体对象就表明一个指定的原始类型。
二. 泛型出现以后的类型
泛型出现以后,扩充了数据类型。从只有原始类型扩充了参数化类型、类型变量类型、泛型限定的的参数化类型 (含通配符+通配符限定表达式)、泛型数组类型。
三. 与泛型有关的类型不能和原始类型统一到Class的缘由
[1]. 【产生泛型擦除的缘由】
原本新产生的类型+原始类型都应该统一成各自的字节码文件类型对象。可是因为泛型不是最初Java中的成分。若是真的加入了泛型,涉及到JVM指令集的修改,这是很是致命的。
[2]. 【Java中如何引入泛型】
为了使用泛型的优点又不真正引入泛型,Java采用泛型擦除的机制来引入泛型。Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换的麻烦。可是,一旦编译完成,全部的和泛型有关的类型所有擦除。
[3]. 【Class不能表达与泛型有关的类型】
所以,与泛型有关的参数化类型、类型变量类型、泛型限定的的参数化类型 (含通配符+通配符限定表达式)、泛型数组类型这些类型所有被打回原形,在字节码文件中所有都是泛型被擦除后的原始类型,并不存在和自身类型一致的字节码文件。因此和泛型相关的新扩充进来的类型不能被统一到Class类中。
[4]. 与泛型有关的类型在Java中的表示
为了经过反射操做这些类型以迎合实际开发的须要,Java就新增了ParameterizedType,GenericArrayType,TypeVariable 和WildcardType几种类型来表明不能被归一到Class类中的类型可是又和原始类型齐名的类型。
[5]. Type的引入:统一与泛型有关的类型和原始类型Class
【引入Type的缘由】为了程序的扩展性,最终引入了Type接口做为Class,ParameterizedType,GenericArrayType,TypeVariable和WildcardType这几种类型的总的父接口。这样实现了Type类型参数接受以上五种子类的实参或者返回值类型就是Type类型的参数。
【Type接口中没有方法的缘由】从上面看到,Type的出现仅仅起到了经过多态来达到程序扩展性提升的做用,没有其余的做用。所以Type接口的源码中没有任何方法。