专栏首页好好学java的技术栈Java如何优雅获取泛型类型

Java如何优雅获取泛型类型

作者:莫那·鲁道
原文:http://thinkinjava.cn/2018/05/Java-%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96%E6%B3%9B%E5%9E%8B%E7%B1%BB%E5%9E%8B/

前言

在 Java 开发中,获取泛型这种操作虽不是很常用,但有时确实必须的,比如 将Json 字符串反序列化成对象的时候。今天就来介绍这个操作。

场景

假设我们定义了一个类,内部有一个数据结构,泛型为 T,当我们输入一个 Json 字符串,想把这个 Json 反序列化成对象,那么此时,我们就需要知道这个泛型的类型。

具体代码场景如下:

抽象父类(包含泛型):

abstract class Base<T extends Comparable<T>> { T data; public Base(String json) {
   this.data = JsonUtil.toObject(json, deSerializable());
 }}

我们想在该类中输入 Json,并将字符串反序列化成对象。比如下面这样:

/**
* 子类定义了父类
*/class Son extends Base<DataClass> { public Son(String json) {
   super(json);
 }}/**
* 数据类型继承Comparable
*/class DataClass implements Comparable<DataClass> { @Override
 public int compareTo(DataClass o) {
   return 0;
 }}

上面的例子中,子类定义了泛型,但获取泛型类型是在父类。

所以,重点在 deSerializable() 方法的实现,我们需要一个 Class 让 Json 工具能够正常序列化。

如何实现?

先说结论:通过 Java 反射包的 ParameterizedType 工具获得泛型具体类型。

例如:下面的代码:

  public static void main(String[] args) {
   String json = JsonUtil.toJson(new DataClass());
   Son s = new Son(json);
   Type t = s.getClass().getGenericSuperclass();
   if (t instanceof ParameterizedType) {
     System.out.println(t);
     // output: cn.think.in.java.clazz.loader.generics.Base<cn.think.in.java.clazz.loader.generics.DataClass>
     for (Type type : ((ParameterizedType) t).getActualTypeArguments()) {
       System.out.println(type);
       //output: class cn.think.in.java.clazz.loader.generics.DataClass
     }
   }
 }

首先我们将一个对象序列化成 Json 字符串,模拟外部输入。然后呢?创建一个子类对象,得到这个 Son 的 Class 。 关键地方来了,调用 getGenericSuperclass 方法,这个方法的作用是:返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type。

所以这里会得到一个 ParameterizedTypeImpl 类型的对象。注意:这个类是 Sun 包下的,不是开源的。该类有以下几个属性:

Type[] 数组就是该类(我们这里是父类)的泛型,rawType 是原始类型,即 Base 的 Class 类型。而 OwnerType 返回的则是 Base 类型。

然后呢,判断这个 t 是不是 ParameterizedType 接口的实现类。如果是,调用 getActualTypeArguments 方法,返回一个 Type数组,即上图的 actualTypeArguments 属性。

而返回的 Type 数组就是父类的泛型 Class。因为 Class 实现了 Type 接口。为什么是数组呢?因为每个类可以有多个泛型。

通过这样几行代码,我们就得到了泛型。当然,这种用法很少。

现在我们知道了如何得到泛型,那么,就将刚刚的场景中的问题解决。

实现反序列化方法:

  private Class<T> deSerializable() {
   Type type = getClass().getGenericSuperclass();
   if (type instanceof ParameterizedType) {
     ParameterizedType parameterizedType = (ParameterizedType) type;
     System.out.println(parameterizedType.getActualTypeArguments()[0]);
     return (Class<T>) parameterizedType.getActualTypeArguments()[0];
   }
   throw new RuntimeException();
 }

获取到当前类(Son)的泛型 Class,获取到泛型数组,返回第一个(因为我们只有一个泛型)泛型类型的 Class。 然后,使用 Json 工具传入 Json 字符串和 Class 类型并返回实体对象。

这样就能够保证编译不会错误,且高度灵活。

这里有一个地方需要注意:Java 的泛型是会在运行期擦除的,但并不总是擦除成 Object ,而是擦除到上限类型。 如果时获取接口的泛型则是调用 Class 的 getGenericInterfaces 方法得到接口集合的泛型。

总结

因为历史原因,Java 的泛型一直是个痛点,但无法避免,所以使用起来确实有点麻烦。但通过 Class 类的众多反射功能,我们还是能够处理泛型的问题。

我们今天使用反射得到了一个类的泛型,并在父类进行处理,成功的将一个字符串反序列化成一个对象。

很干!必须好看☟

本文分享自微信公众号 - 好好学java(SIHAIloveJAVA)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-01-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 学多线程的看过来,带你学习多线程中断机制

    当我们点击某个杀毒软件的取消按钮来停止查杀病毒时,当我们在控制台敲入quit命令以结束某个后台服务时……都需要通过一个线程去取消另一个线程正在执行的任务。Jav...

    好好学java
  • 我简历上的Java项目都好low,怎么办?

    目录:

    好好学java
  • 听说,这样学习技术最有效果

    好好学java
  • Java如何优雅获取泛型类型

    在 Java 开发中,获取泛型这种操作虽不是很常用,但有时确实必须的,比如 将Json 字符串反序列化成对象的时候。今天就来介绍这个操作。

    Spark学习技巧
  • Java如何优雅获取泛型类型

    在 Java 开发中,获取泛型这种操作虽不是很常用,但有时确实必须的,比如 将Json 字符串反序列化成对象的时候。今天就来介绍这个操作。

    黄泽杰
  • Python之Bilibili自动更新邮件提醒并任务栏图标「完整代码」

    本次分享的是小编经过多日编写的关于自动检测B站Up主视频更新情况,并发送邮件提醒更新的Python程序,代码不专业、部分代码段借鉴网上,仅供参考娱乐!

    小锋学长
  • 科技周报:马斯克说自己的AI芯片世界最强;传小米商谈IPO估值达千亿

    赵子潇/文 一周科技大事件 1.马斯克:特斯拉正开发人工智能芯片 是“全球最棒” 特斯拉CEO埃隆·马斯克(Elon Musk)周四在一场学术和行业研究人员会议...

    企鹅号小编
  • 微服务RESTful接口文档生成神器Swagger初探

    在微服务构建的过程中,你也许发现写的那些restful风格的接口需要编写文档。 文档一般包括要输入哪些参数,哪些参数是必填的,哪些是选填的。还有返回结果的格式...

    ImportSource
  • 用Python进行gRPC接口测试(三)

    在近期的测试中,小编又遇到了一些关于grpc接口的测试,踩了一些坑,也总结了一些经验,想与大家分享交流一下。本期我们主要来谈谈有关protobuf中一些特殊数据...

    用户5521279
  • 数据泄露事件频发,企业如何做好数据保护?

    2020年4月1日,万豪国际首次披露今年2月底检测到的数据泄露事件,近520万房客个人信息被泄露,数据涉及个人姓名、地址、电话号码以及会员账户信息、伙伴关系与...

    腾讯云安全

扫码关注云+社区

领取腾讯云代金券