文档章节

利用反射操作泛型

0909
 0909
发布于 2016/08/16 17:26
字数 2087
阅读 29
收藏 0
点赞 0
评论 0

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

Type直接子接口

  • java.lang.reflect.ParameterizedType : 表示一种参数化的类型,比如Collection<String>
  • java.lang.reflect.GenericArrayType : 表示一种元素类型是参数化类型或者类型变量的数组类型
  • java.lang.reflect.WildcardType : 是各种类型变量的公共父接口
  • java.lang.reflect.TypeVariable : 代表一种通配符类型表达式, 比如_?, ? extends Number, ? super Integer_ ( wildcard:“通配符” )

所有类型都是Type类型子类

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

ParameterizedType 接口类型的含义

表示参数化类型。比如:Map<String, Date>这种参数化类型 获取参数化类型<>中的实际类型 源码声明:Type[] getActualTypeArguments(); 【注意】无论<>中有几层<>嵌套,这个方法仅仅脱去最外层的<>之后剩下的内容就作为这个方法的返回值。

**_ArrayList<ArrayList<Integer>> al1 _ ** 通过getActualTypeArguments()返回之后,脱去最外层的<>之后,剩余的类型是ArrayList<Integer>。因此对这个参数的返回类型是ParameterizedType。

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

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

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

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

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

GenericArrayType 接口类型的含义

表示泛型数组类型。比如:void method(ArrayList<String>[] al){…} 【注意】<>不能出现在数组的初始化中,即new数组之后不能出现<>,否则javac无法通过。但是作为引用变量或者方法的某个参数是完全可以的。 获取泛型数组中元素的类型 源码声明:Type getGenericComponentType(); 【注意】无论从左向右有几个[]并列,这个方法仅仅脱去最右边的[]之后剩下的内容就作为这个方法的返回值。为什么返回值类型是Type?

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

**_E[] _ ** p2 通过getComponentType()返回之后,脱去最右边的[]之后,剩余的类型是E。因此对这个参数的返回类型是TypeVariable。

ArrayList<E>[] p3 通过getComponentType()返回之后,脱去最右边的[]之后,剩余的类型是ArrayList<E>。因此对这个参数的返回类型是ParameterizedType。

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

**TypeVariable 接口类型的含义 **

表示类型参数或者又叫做类型变量。比如:<E>void method(E e){}中的E就是类型变量 获取类型变量的泛型限定的上边界的类型 源码声明:Type[] getActualTypeArguments();

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

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

例如下面的方法: public static <E extends Map<String, Date>& Cloneable&Serializable> E methodVI(E e){…} E的第一个上边界是Map<String, Date>,是ParameterizedType类型 E的第二个上边界是Cloneable,是Class类型 因此,为统一,返回值的数组的元素类型就是Type

WildcardType接口类型的含义

表示通配符类型的表达式。 比如 void printColl(ArrayList<? extends Number>al); 中的 ? extends Number

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

获取通配符表达式对象的泛型限定的上边界的类 源码声明:Type[] getUpperBounds(); 【注意】上面说了,现阶段返回的Type[ ]中的数组大小就是1个。写成Type[ ]是为了语言的升级而进行的扩展。

public static voidprintColl(ArrayList<?extends ArrayList<String>> al){}

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

public static <E> voidprintColl(ArrayList<?extends E> al){}

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

public static <E> voidprintColl(ArrayList<?extends E[]> al){}

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

public static <E> voidprintColl(ArrayList<?extends Number> 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接口的源码中没有任何方法。

© 著作权归作者所有

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

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

sshpp ⋅ 2017/07/24 ⋅ 0

Java 泛型,你了解类型擦除吗?

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

xiaomin0322 ⋅ 06/06 ⋅ 0

Java学习日常:泛型

附上思维导图。这篇博客主要讲了如下知识点。 泛型的思维导图 看完了《Thinking in Java》的第十五章泛型,着实被震了一惊。看之前以为泛型就是泛型,看完之后却发现Java的泛型是通过编译时的...

Happioo ⋅ 2017/11/10 ⋅ 0

java泛型-类型擦除

最近了解了一下java的泛型,了解到了“类型擦除”这个东西,现做个简单小结。 java泛型实现的原理可以说就是类型擦除 可以这么理解,如ArrayList<Integer>在编译后变成了ArrayList<Object>,...

liujiest ⋅ 2016/08/03 ⋅ 0

Java基础巩固笔记(2)-泛型

Contents java基础巩固笔记(2)-泛型 术语 "?"通配符 自定义泛型方法 自定义泛型类 泛型和反射 本文对泛型的基本知识进行较为全面的总结,并附上简短的代码实例,加深记忆。 泛型:将集合中的...

卟想苌亣 ⋅ 2017/11/23 ⋅ 0

说说 Spring 的容器事件体系

Spring 的 ApplicationContext 能够发布事件并且允许注册相应的事件监听器,它拥有一套完善的事件发布和监听机制。 在事件体系中有这些概念: 事件: java.util.EventObject。 监听器:java....

deniro ⋅ 05/29 ⋅ 0

关于java反射的问题

需求是这样的,集合对象做为参数传入方法,能不能利用java反射获取集合对象泛型的实际类型 例如:getType(List objectList) 有没有方法获取实际传入参数的泛型T的实际类型?...

我就是个菜 ⋅ 2015/12/03 ⋅ 4

Hibernate反射DAO模式

在持久层框架中,如果我们要像简单的JDBC连接数据库那样写一个通用的Dao方法的话,那么把JDBC简单的业务逻辑搬到hibernate持久层框架中,当然是不可能的,这里主要的问题就在于hibernate持久...

zretc ⋅ 2013/07/19 ⋅ 0

Java高级特性入门——泛型、反射和注解!

摘要: 只有掌握了Java的高级特性,这门语言才算真正地登堂入室。本文将带领大家一同了解Java语言的三个常用的高级特性——泛型、反射和注解。 专家简介: 澳明 ,阿里巴巴高级开发工程师,来...

Java高级架构 ⋅ 05/28 ⋅ 0

Java中的泛型方法

泛型是什么意思在这就不多说了,而Java中泛型类的定义也比较简单,例如:public class Test<T>{}。这样就定义了一个泛型类Test,在实例化该类时,必须指明泛型T的具体类型,例 如:Test<Obje...

fjabing ⋅ 2014/02/16 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Thrift RPC实战(二) Thrift 网络服务模型

TServer类层次体系 TSimpleServer/TThreadPoolServer是阻塞服务模型 TNonblockingServer/THsHaServer/TThreadedSelectotServer是非阻塞服务模型(NIO) 1 TServer抽象类的定义 内部静态类Args的...

lemonLove ⋅ 6分钟前 ⋅ 0

vim命令用法

第五章 vim命令 vim和vi几乎是一样的,唯一的区别就是当编辑一个文本时,使用vi不会显示颜色,而使用vim会显示颜色。 vim有三个模式:一般模式,编辑模式,命令模式。 系统最小化安装时没有安...

弓正 ⋅ 7分钟前 ⋅ 0

MyBatis源码解读之配置

1. 目的 本文主要介绍MyBatis配置文件解析,通过源码解读mybatis-config.xml(官方默认命名)、Mapper.xml 与Java对象的映射。 2. MyBatis结构 查看大图 MyBatis结构图,原图实在太模糊了,所以...

无忌 ⋅ 11分钟前 ⋅ 0

Ignite的jdbc与网格的连接方式的查询性能对比

环境: 数据量100万 Ignite2.5 Windows10 8g jdbc方式连接 import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; i......

仔仔1993 ⋅ 25分钟前 ⋅ 0

收集自网络的wordpress 分页导航的代码教程(全网最全版)

wordpress 分页导航是用来切换文章的一个功能,添加了 wordpress 分页导航后,用户即可自由到达指定的页面数浏览分类文章,而这样的一个很简单功能却有很多朋友在用插件:WP-PageNavi,插件的...

Rhymo-Wu ⋅ 41分钟前 ⋅ 0

微服务 WildFly Swarm 入门

Hello World 就像前面章节中的其他框架一样,我们希望添加一些基本的 Hello-world 功能,然后在其上逐步添加更多的功能。让我们从在我们的项目中创建一个 HolaResources 开始。您可以使用您的...

woshixin ⋅ 48分钟前 ⋅ 0

Maven的安装和Eclipse的配置

1. 下载Maven 下载地址 2. 解压压缩包,放到自己习惯的硬盘中 此处我将其放到了 D:\Tools 目录下。 3. 配置环境变量 右键此电脑 -> 属性 -> 高级系统设置 -> 环境变量。 在系统变量中新建,变...

影狼 ⋅ 55分钟前 ⋅ 0

python pip使用国内镜像的方法

国内源 清华:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 华中理工大学:http://......

良言 ⋅ 56分钟前 ⋅ 0

对于url变化的spa应该如何使用微信jssdk

使用vue单页面碰上微信jssdk config验证失败的坑。第一次成功 之后切换页面全部失败,找到了解决方法,第一次验证成功后保存验证信息 切换页面时验证信息直接拿来用,加一个wx.error() 失败时...

孙冠峰 ⋅ 今天 ⋅ 0

Spring Cloud Gateway 一般集成

SCF发布,带来很多新东西,不过少了点教程,打开方式又和以前的不一样,比如这个SCG,压根就没有入门指导,所以这里写一个,以备后用。 一、集成 pom.xml <dependency> <groupI...

kut ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部