利用反射操做泛型

反射+泛型有关的接口类型

Type直接子接口java

  • java.lang.reflect.ParameterizedType : 表示一种参数化的类型,好比Collection<String>, Collection<T> Collection<T[]>等
  • java.lang.reflect.GenericArrayType : 表示一种元素类型是参数化类型或者类型变量的数组类型, 好比 T[] 
  • java.lang.reflect.WildcardType : 表明一种通配符类型表达式, 好比?, ? extends Number, ? super Integer ( wildcard:“通配符” )
  • java.lang.reflect.TypeVariable :是各类类型变量的公共父接口, Collection<T> 中的T, 可经过Class.getTypeParametes得到

全部类型都是Type类型子类数组

  • 原始类型 (raw types)【对应Class】
  • 参数化类型 (parameterizedtypes)【对应ParameterizedType】
  • 参数化数组类型 (array types)【对应GenericArrayType】
  • 类型变量 (type variables)【对应TypeVariable】
  • 基本数据类型(primitivetypes)【仍然对应Class】

ParameterizedType 接口类型的含义

表示参数化类型。好比: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.(上面那两个最经常使用)

GenericArrayType 接口类型的含义

表示泛型数组类型。好比: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

WildcardType接口类型的含义

表示通配符类型的表达式。 好比 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做为数组的元素类型。

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接口的源码中没有任何方法。

相关文章
相关标签/搜索