文档章节

利用反射操作泛型

叶易
 叶易
发布于 2016/08/16 17:26
字数 2400
阅读 31
收藏 0

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

Type直接子接口

  • 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。

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

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

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

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

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

方法:

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

© 著作权归作者所有

共有 人打赏支持
叶易
粉丝 22
博文 24
码字总数 30959
作品 0
无锡
Java--反射的逐步理解

层层引入反射的作用 一.类类型的概念:所有类都是对象,是Class类的实例对象,这个对象我们成为该类的类类型 1.下面是一个小的test,以产生3种方式的类类型: foo user = Class c1 = foo. C...

sshpp
2017/07/24
0
0
手写Android序列化框架FastJson(简易版)

开篇废话 近期利用业余时间,跟着大神把FastJson的框架学习了一下,在这里,记录一下这次学习的心得。 FastJson是一个Json处理工具包,包括“序列化”和“反序列化”两部分。这次学习 ,大概...

进击的欧阳
06/22
0
0
Java 泛型,你了解类型擦除吗?

泛型,一个孤独的守门者。 大家可能会有疑问,我为什么叫做泛型是一个守门者。这其实是我个人的看法而已,我的意思是说泛型没有其看起来那么深不可测,它并不神秘与神奇。泛型是 Java 中一个...

xiaomin0322
06/06
0
0
Java语言学习(十一):枚举类型和泛型

Java中一个重要的类型:枚举,它可以用来表示一组取值范围固定的变量,使用 enum 关键字定义枚举类型,其中元素不能重复,通常大写表示。利用Java的反射机制,可以在运行时分析类,如查看枚举...

海岸线的曙光
07/18
0
0
java基础强化——深入理解反射

目录 1.从Spring容器的核心谈起 2. 反射技术初探 2.1 什么是反射技术 2.2 类结构信息和java对象的映射 3 Class对象的获取及需要注意的地方 4. 运行时反射获取类的结构信息 5. 运行时反射获取...

takumiCX
07/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

svn 常用操作命令及问题处理

1. 常用命令 1.1. 基本使用 检出 checkout ➜ svn co repo_url -m '检出代码'➜ svn co repo_url saved_dir_name -m '检出代码,并指定目录名' 加入版本控制 add # 添加指定文件➜ svn...

whoru
44分钟前
3
0
记一次jquery validate的扩展(第一次失去焦点时触发校验)

最近在用jquery.validate 做前端表单校验,但是发现每次第一次失去焦点时,如果文本框内容为空,且该字段是必填项, 则不会触发校验,直到提交表单后,再次失去焦点时,才会触发,想对此进行...

foreach
48分钟前
1
0
java生成UUID

UUID介绍: UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。按照开放软件基金会(OSF)制定的标准计算,用到了以...

编程SHA
51分钟前
1
0
Docker Compose 原理

Docker 的优势非常明显,尤其是对于开发者来说,它提供了一种全新的软件发布机制。也就是说使用 docker 镜像作为软件产品的载体,使用 docker 容器提供独立的软件运行上下文环境,使用 dock...

Java干货分享
今天
2
0
解决过滤器中设置cookie无效的问题

解决过滤器中设置cookie无效的问题 代码现场 filterChain.doFilter(sessionSyncRequestWrapper, response);Cookie emailCook = WebServletUtil.getSelectedCookie(request.getCookies(), ......

黄威
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部