Java 泛型之 Type 体系

本贴最后更新于 2721 天前,其中的信息可能已经水流花落

Type 是 java 类型信息体系中的顶级接口,其中 Class 就是 Type 的一个直接实现类。此外,Type 还有有四个直接子接口:ParameterizedType,TypeVariable,WildcardType,GenericArrayType。

这几个接口的介绍如下:

  • Type

它是所有类型的公共接口。包括原始类型、参数化类型、数组类型、类型变量和基本类型。ParameterizedType, TypeVariable, WildcardType,GenericArrayType 这四个接口都是它的子接口。

  • GenericDeclaration

这个接口 Class、Method、Constructor 都有实现,我们就是要用这个接口的 getTypeParameters 方法,它返回一个 TypeVariable[]数组,这个数组里面就是我们定义的类型变量 T 和 K,顺序与我们声明时一样。如果用循环语句将数组打印出来,你会发现只会输出 T 和 K,这可不是我们想要的结果,那么想要获得预期的结果怎么办呢?请继续往下看。

  • TypeVariable

它表示类型变量。比如 T,比如 K extends Comparable<? super T> & Serializable,这个接口里面有个 getBounds()方法,它用来获得类型变量上限的 Type 数组,如果没有定义上限,则默认设定上限为 Object,请注意 TypeVariable 是接口,实际得到的是 TypeVariableImpl 实现类,下面几个接口都一样。

拿 T 和 K 来说明,T 没有定义任何上限,所以它就有一个默认上限 java.lang.Object,实际跟踪代码的时候你会发现 T 的 bounds 属性为空,只有在调用了 getBounds()方法后,才会有一个 Type[1]数组[class java.lang.Object]。而对于 K 来说,调用了 getBounds 方法后,得到的数组是[java.lang.Comparable<? super T>, interface java.io.Serializable],它们的类型却是不一样的,第 1 个是 ParameterizedType,而第二个是 Class.

  • ParameterizedType

ParameterizedType 表示参数化类型,就是上面说的 java.lang.Comparable<? super T>,再比如 List,List,这些都叫参数化类型。得到 Comparable<? super T> 之后,再调用 getRawType()与 getActualTypeArguments()两个方法,就可以得到声明此参数化类型的类(java.lang.Comparable)和实际的类型参数数组([? super T]),而这个? super T 又是一个 WildcardType 类型。

  • WildcardType

它用来描述通配符表达式,上面返回的? super T 正好是这个类型。然后调用 getUpperBounds()上限和 getLowerBounds()下限这两个方法,获得类型变量?的限定类型(上下限),对于本例的通配符(?),它的上限为 java.lang.Object,下限为 T

通过上面几个接口的分析,可以将 Person 类的泛型参数都解析出来,那么 Person 的超类以及实现的接口该怎么处理呢?Class 类里面同样在 1.5 版本加入了 getGenericSuperclass()与 getGenericInterfaces()两个方法,用于返回带参数化类型的超类与接口。

GenericArrayType 其实就是泛型数组类型。

我们说 Class 在一定程度上挽救了擦除的类型信息,我们就可以通过这几个接口来获取被擦除的类型参数信息,这几个接口无非就是对类型参数的一个分类,通过它们提供的一些方法,我们可以逐步的获取到最原始的类型参数的 Class 对象。

具体的说明和 API 大家可以去看文档,我这里记录一个实际的应用,当然在各种框架中的应用比比皆是。

在 JavaEE 的 Dao 层我们一般都会封装出一个通用的泛型 BaseDao,它可以实现对各种实体例如 User,Order 的基本 CRUD,然后具体的 UserDao,OrderDao 等等会去继承它,提供其他的 Dao 方法:

public class UserDao extends BaseDao<User>{}

我们使用的 BaseDao 是基于 DBUtils 的,它需要实体的 Class 对象才能进行通用的查询方法,例如 User 的 Class 对象,我们可以通过构造函数,函数参数等手段传递给 BaseDao,但是有了反射,可以有更优雅的实现。

public class BaseDao<T> { private Class<T> clszz; public BaseDao(){ Type type = this.getClass().getGenericSuperclass();//拿到带类型参数的泛型父类 if(type instanceof ParameterizedType){//这个Type对象根据泛型声明,就有可能是4中接口之一,如果它是BaseDao<User>这种形式 ParameterizedType parameterizedType = (ParameterizedType) type; Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();//获取泛型的类型参数数组 if(actualTypeArguments != null && actualTypeArguments.length == 1){ if(actualTypeArguments[0] instanceof Class){//类型参数也有可能不是Class类型 this.clszz = (Class<T>) actualTypeArguments[0]; }else{ //例如: BaseDao<BaseDao<User>>,获取到的就不是Class,而又是ParameterizedType,即嵌套的 ParameterizedType,一层一层剥开,最终是可以得到User的Class对象的 } } } } public T get(String sql,Object...params){ QueryRunner qr = new QueryRunner(); T obj; Connection connection; try { connection = JdbcUtil.getConnection(); obj = qr.query(connection,sql,new BeanHandler<T>(clszz),params); } catch (SQLException e) { e.printStackTrace(); return null; } return obj; } }
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3201 引用 • 8217 回帖 • 1 关注
  • class
    4 引用 • 3 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 661 关注
  • OneDrive
    2 引用 • 5 关注
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 409 关注
  • V2Ray
    1 引用 • 15 回帖 • 4 关注
  • 房星科技

    房星网,我们不和没有钱的程序员谈理想,我们要让程序员又有理想又有钱。我们有雄厚的房地产行业线下资源,遍布昆明全城的 100 家门店、四千地产经纪人是我们坚实的后盾。

    6 引用 • 141 回帖 • 611 关注
  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    268 引用 • 666 回帖 • 4 关注
  • Firefox

    Mozilla Firefox 中文俗称“火狐”(正式缩写为 Fx 或 fx,非正式缩写为 FF),是一个开源的网页浏览器,使用 Gecko 排版引擎,支持多种操作系统,如 Windows、OSX 及 Linux 等。

    7 引用 • 30 回帖 • 376 关注
  • 小薇

    小薇是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动。

    由于 Smart QQ 从 2019 年 1 月 1 日起停止服务,所以该项目也已经停止维护了!

    35 引用 • 468 回帖 • 764 关注
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 563 关注
  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 266 关注
  • Vim

    Vim 是类 UNIX 系统文本编辑器 Vi 的加强版本,加入了更多特性来帮助编辑源代码。Vim 的部分增强功能包括文件比较(vimdiff)、语法高亮、全面的帮助系统、本地脚本(Vimscript)和便于选择的可视化模式。

    29 引用 • 66 回帖
  • Scala

    Scala 是一门多范式的编程语言,集成面向对象编程和函数式编程的各种特性。

    13 引用 • 11 回帖 • 153 关注
  • JRebel

    JRebel 是一款 Java 虚拟机插件,它使得 Java 程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。

    26 引用 • 78 回帖 • 682 关注
  • 音乐

    你听到信仰的声音了么?

    62 引用 • 512 回帖
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 368 关注
  • JSON

    JSON (JavaScript Object Notation)是一种轻量级的数据交换格式。易于人类阅读和编写。同时也易于机器解析和生成。

    53 引用 • 190 回帖 • 1 关注
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    29 引用 • 202 回帖 • 29 关注
  • 数据库

    据说 99% 的性能瓶颈都在数据库。

    346 引用 • 757 回帖 • 1 关注
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    188 引用 • 319 回帖 • 239 关注
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    91 引用 • 59 回帖
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖 • 2 关注
  • Sphinx

    Sphinx 是一个基于 SQL 的全文检索引擎,可以结合 MySQL、PostgreSQL 做全文搜索,它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索。

    1 引用 • 224 关注
  • 黑曜石

    黑曜石是一款强大的知识库工具,支持本地 Markdown 文件编辑,支持双向链接和关系图。

    A second brain, for you, forever.

    25 引用 • 248 回帖
  • Visio
    1 引用 • 2 回帖 • 2 关注
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • PWA

    PWA(Progressive Web App)是 Google 在 2015 年提出、2016 年 6 月开始推广的项目。它结合了一系列现代 Web 技术,在网页应用中实现和原生应用相近的用户体验。

    14 引用 • 69 回帖 • 186 关注
  • 印象笔记
    3 引用 • 16 回帖