`

JAVA Type体系与泛型的获取

 
阅读更多
本文主要部分为转载,但修正了部分文字错误,并删除了一些自己认为不太恰当的结论。    

 

一、概述

  java.lang.reflect.Type:java语言中所有类型的公共父接口

  1. Type直接子接口

     ParameterizedType,GenericArrayType,TypeVariable和WildcardType四种类型的接口

  • ParameterizedType: 表示一种参数化的类型,即拥有泛型定义的类型,比如HibernateDao或者Collection.  
  • GenericArrayType: 表示一种元素类型参数化类型或者类型变量数组类型
  • TypeVariable: 是各种类型变量公共父接口.如你定义了一个参数化类型 User<T>, 则T便是类型变量
  • WildcardType: 代表一种通配符类型表达式,比如?, ? extends Number, ? super Integer
  • 【wildcard是一个单词:就是“通配符”】

   2Type直接实现子类 :Class类

 

   3. java.lang.reflect.Type接口

        Type所有类型指代的有:原始类型 (raw types)【对应Class】参数化类型 (parameterizedtypes)【对应ParameterizedType】, 数组类型 (array types)【对应GenericArrayType】,类型变量 (type variables)【对应TypeVariable】,基本数据类型(primitivetypes)【仍然对应Class】

 

二、详解

 

 1. java.lang.reflect.ParameterizedType接口

   表示参数化类型。比如:Map<String>这种参数化类型

   通过 Type[] ParameterizedType.getActualTypeArguments(); 获取参数化类型<>中的实际类型

【注意】无论<>中有几层<>嵌套,这个方法仅仅脱去最外层<>之后剩下的内容就作为这个方法的返回值

方法定义:

 

public <E> void typeTestMethod(  
ArrayList<ArrayList<ArrayList> al1,
ArrayList<E> al2,
ArrayList<String> al3,
ArrayList<? extends Number> al4,
ArrayList<E[]> al5);

 

 

那么他的每一参数总体上看都是参数化类型的。

{1}. 对于ArrayList<ArrayList<ArrayList> al1,通过getActualTypeArguments()返回之后,脱去最外层的<>之后,剩余的类型是ArrayList因此对这个参数的返回类型是ParameterizedType

{2}. 对于ArrayList<E> al2,通过getActualTypeArguments()返回之后,脱去最外层的<>之后,剩余的类型是E因此对这个参数的返回类型是TypeVariable

{3}. ArrayList<String> al3;,通过getActualTypeArguments()返回之后,脱去最外层的<>之后,剩余的类型是String因此对这个参数的返回类型是Class

{4}. 对于ArrayList<? extends Number> al4,通过getActualTypeArguments()返回之后,脱去最外层的<>之后,剩余的类型是? ExtendsNumber因此对这个参数的返回类型是WildcardType

{5}. 对于ArrayList<E[]> al5,通过getActualTypeArguments()返回之后,脱去最外层的<>之后,剩余的类型是E[]因此对这个参数的返回类型是GenericArrayType

所以,可能获得各种各样类型的实际参数,所以为了统一,采用直接父类数组Type[]进行接收。

 

2. java.lang.reflect. GenericArrayType接口   

表示泛型数组类型比如:void method(ArrayList[] al){…}

【注意】  数组本身没有泛型。所谓GenericArrayType,严格的说,指的还是普通的数组,只不过带上了Generic前缀,意味着不丢失数组类型的泛型信息,即ArrayList的泛型信息不会丢失。

获取泛型数组元素类型  :  Type  GenericArrayType.Type getGenericComponentType();

【注意】无论从左向右有几个[]并列,这个方法仅仅脱去最右边[]之后剩下的内容就作为这个方法的返回值

为什么返回值类型Type

public <E> typeTest(

String[] p1,

E[] p2,

ArrayList[] p3,

E[][] p4); 

 

 

{1}. 对于String[] p1,通过getComponentType()返回之后,脱去最右边的[]之后,剩余的类型是String因此对这个参数的返回类型是Class

{2}. 对于E[] p2,通过getComponentType()返回之后,脱去最右边的[]之后,剩余的类型是E因此对这个参数的返回类型是TypeVariable

{3}. 对于ArrayList[] p3,通过getComponentType()返回之后,脱去最右边的[]之后,剩余的类型是ArrayList因此对这个参数的返回类型是ParameterizedType

{4}. 对于E[][]  p4,通过getComponentType()返回之后,脱去最右边的[]之后,剩余的类型是E[]因此对这个参数的返回类型是GenericArrayType

 

3. java.lang.reflect.TypeVariable接口   

表示类型参数或者又叫做类型变量。比如:void method(E e){}中的E就是类型变量

获取类型变量的泛型限定上边界的类型

源码声明:Type[] getBounds()

【注意】这里面仅仅是上边界。原因就是类型变量定义的时候只能使用extends进行()边界限定不能使用super,否则编译无法通过。同时extends给出的都是类型变量上边界

为什么是返回类型是数组?因为类型变量可以通过&进行多个上边界限定,因此上边界有多个,因此返回值类型是数组类型[ ]

例如下面的方法:

public static <E extends Map<String>& Cloneable&Serializable > void method(E e){…}

E的第一个上边界是Map<String>,是ParameterizedType类型

E的第二个上边界是Cloneable,是Class类型

因此,为统一,返回值的数组的元素类型就是Type

 

4. java.lang.reflect.WildcardType接口   

表示通配符类型的表达式

比如 void printColl(ArrayList<? extends Number> al); 中的 ? extends Number

注意】根据上面API的注释提示:现阶段通配符表达式仅仅接受一个上边界或者下边界,这个和定义类型变量时候可以指定多个上边界是不一样。但是API说了,为了保持扩展性,这里返回值类型写成了数组形式。实际上现在返回的数组的大小就是1

获取通配符表达式对象的泛型限定上边界的类型

源码声明:Type[] getUpperBounds();

                  Type[] getLowerBounds();

【注意】上面说了,现阶段返回的Type[ ]中的数组大小就是1个。写成Type[ ]是为了语言的升级而进行的扩展。

例如下面的方法:

{1}. public static void printColl(ArrayList<? extends ArrayList> al){}

通配符表达式是:? extends ArrayList,这样 extends后面是?的上边界,这个上边界是ParameterizedType类型。

{2}. public static  void printColl(ArrayList<? extends E> al){}

通配符表达式是:? extends E,这样 extends后面是?的上边界,这个上边界是TypeVariable类型

{3}.public static  void printColl(ArrayList<? extends E[]> al){}

通配符表达式是:? extends E[],这样 extends后面是?的上边界,这个上边界是GenericArrayType类型

{4}.public static  void printColl(ArrayList<?  extends Number> al){}

通配符表达式是:? extends Number,这样 extends后面是?的上边界,这个上边界是Class类型

最终统一成Type作为数组的元素类型。

 

三、TYPE体系历史 

  1.. 泛型出现之前的类型

没有泛型的时候,只有所谓的原始类型。此时,所有的原始类型都通过字节码文件类Class进行抽象Class类的一个具体对象就代表一个指定的原始类型

 

 

  2. 泛型出现之后的类型

泛型出现之后,扩充了数据类型。从只有原始类型扩充了参数化类型类型变量类型泛型限定的的参数化类型 (通配符+通配符限定表达式)泛型数组类型

 

 

 3.  引入type的原因

为了程序的扩展性,最终引入了Type接口作为ClassParameterizedTypeGenericArrayTypeTypeVariableWildcardType这几种类型的总的父接口。这样实现了Type类型参数接受以上五种子类的实参或者返回值类型就是Type类型的参数。

Type接口中没有方法的原因

从上面看到,Type的出现仅仅起到了通过多态来达到程序扩展性提高的作用,没有其他的作用。因此Type接口的源码中没有任何方法。

 

分享到:
评论

相关推荐

    Java如何获取泛型类型

    参考:我眼中的Java-Type体系(1) 我眼中的Java-Type体系(2) 秒懂Java类型(Type)系统 Java 运行时如何获取泛型参数的类型 Java类型Type 之 ParameterizedType,GenericArrayType,TypeVariabl,WildcardType 从实现...

    JAVA上百实例源码以及开源项目源代码

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    JAVA上百实例源码以及开源项目

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    java开源包4

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包101

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包11

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包6

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包9

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包8

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包10

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包5

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包1

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包3

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包2

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    java开源包7

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

    Java资源包01

    JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (&lt;jcaptcha:image label="Type the text "/&gt; ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...

Global site tag (gtag.js) - Google Analytics