c++ 泛型_不了解Java泛型Type体系?看看网易大神踩过的坑

本文详细介绍了Java泛型的类型体系,包括泛型类、接口、方法以及泛型擦除的概念。泛型在编译时用于提升代码的可读性和安全性,但在运行时被擦除。通过反射,可以获取泛型的某些信息,如Type接口及其实现类。此外,文章还探讨了如何通过反射获取泛型的实际类型,并提供了相关代码示例。
摘要由CSDN通过智能技术生成

Java泛型Type体系介绍

  • Java泛型
  • 泛型擦除
  • Java反射泛型Type体系

什么是泛型

泛型是jdk5引入的类型机制,就是将类型参数化,泛型机制将类型转换时的类型检查从运行时提前到了编译时,使用泛型编写的代码比杂乱的使用object并在需要时再强制类型转换的机制具有更好的可读性和安全性。

泛型对于集合类尤其有用,如ArrayList。这里可能有疑问,既然泛型为了适应不同的对象,ArrayList本来就可以操作不同类型的对象呀?那是因为没有泛型之前采用继承机制实现的,实际上它只维护了一个Object对象的数组。结果就是对List来说它只操作了一类对象Object,而在用户看来却可以保存不同的对象。

泛型提供了更好的解决办法——类型参数,如:

List list = new ArrayList();

这样解决了几个问题:

  • 可读性,从字面上就可以判断集合中的内容类型;
  • 类型检查,避免插入非法类型。
  • 获取数据时不再需要强制类型转换。

泛型使用:泛型类、泛型接口、泛型方法

泛型擦除

泛型只在编译阶段有效,编译后类型被擦除了,也就是说jvm中没有泛型对象,只有普通对象。所以完全可以把代码编译为jdk1.0可以运行的字节码。

擦除的方式

定义部分,即尖括号中间的部分直接擦除。

public class GenericClass{}

擦除后:public class GenericClass{}

引用部分,其中的T被替换成对应的限定类型(这也是为什么泛型类型不能是基本类型的原因)

public T field1;

擦除后:public Comparable field1;

如果没有限定类型:

public class GenericClass{

public T field1;

}

那么的替换为object,即:

public class GenericClass{

public Object field1;

}

有多个限定符的,替换为第一个限定类型名。如果引用了第二个限定符的类对象,编译器会在必要的时候进行强制类型转换。

public class GenericClass{

public T field1;

}

类擦除后变为:

public class GenericClass{

public Comparable field1;

}

而表达式返回值返回时,泛型的编译器自动插入强制类型转换。

泛型擦除的残留

反汇编:

fd49f1de6cc02e6f79adb347259f032b.png

这就是擦除的残留。

962e00024e8b7420258768b119e8ed2f.png

descriptor:对方法参数和返回值进行描述; signature:泛型类中独有的标记,普通类中没有,JDK5才加入,标记了定义时的成员签名,包括定义时的泛型参数列表,参数类型,返回值等;

这样的机制,对于分析字节码是有意义的。

Java泛型有这么一种规律: (http://rednaxelafx.iteye.com/blog/586212)

  • 位于声明一侧的,源码里写了什么到运行时就能看到什么;
  • 位于使用一侧的,源码里写什么到运行时都没了。

什么意思呢?“声明一侧”包括泛型类型(泛型类与泛型接口)声明、带有泛型参数的方法和域的声明。注意局部变量的声明不算在内,那个属于“使用”一侧。

泛型相关的反射

有了泛型机制,jdk的reflect包中增加了几个泛型有关的类:

2e5ac4f9c06144cb77471cb7b83cbbc8.png

Type

Type是所有类型的父接口, 如原始类型(raw types,对应Class)、 参数化类型(parameterized types, 对应ParameterizedType)、 数组类型(array types,对应GenericArrayType)、 类型变量(type variables, 对应TypeVariable)和基本(原生)类型(primitive types, 对应Class)

子接口有ParameterizedType, TypeVariable, GenericArrayType, WildcardType, 实现类有Class

ParameterizedType

具体的范型类型, 如Map

有如下方法:

  • Type getRawType(): 返回承载该泛型信息的对象, 如上面那个Map承载范型信息的对象是Map
  • Type[] getActualTypeArguments(): 返回实际泛型类型列表, 如上面那个Map实际范型列表中有两个元素, 都是String
  • Type getOwnerType(): 返回是谁的member.(上面那两个最常用)

TypeVariable

类型变量, 范型信息在编译时会被转换为一个特定的类型, 而TypeVariable就是用来反映在JVM编译该泛型前的信息.

它的声明是这样的: public interface TypeVariable extends Type

也就是说它跟GenericDeclaration有一定的联系

TypeVariable是指在GenericDeclaration中声明的、这些东西中的那个变量T、C; 它有如下方法:

  • Type[] getBounds(): 获取类型变量的上边界, 若未明确声明上边界则默认为Object
  • D getGenericDeclaration(): 获取声明该类型变量实体
  • String getName(): 获取在源码中定义时的名字

注意:

类型变量在定义的时候只能使用extends进行(多)边界限定, 不能用super;

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

GenericArrayType

范型数组,组成数组的元素中有范型则实现了该接口; 它的组成元素是ParameterizedType或TypeVariable类型,它只有一个方法:

  • Type getGenericComponentType(): 返回数组的组成对象, 即被JVM编译后实际的对象

WildcardType

该接口表示通配符泛型, 比如? extends Number 和 ? super Integer 它有如下方法:

  • Type[] getUpperBounds(): 获取范型变量的上界
  • Type[] getLowerBounds(): 获取范型变量的下界

注意:

现阶段通配符只接受一个上边界或下边界, 返回数组是为了扩展, 实际上返回的数组的大小是1

反射获取泛型相关信息

在Java泛型的这四种形式中,类型变量和类型变量数组还有通配符类型表达式都是取不到泛型参数的实际类型的,只有泛型的参数化类型和参数化类型数组中的实际类型可以得到实际类型,并可用于实例化,也就是说只有前两种情况GenericArrayType和ParameterizedType才有可能得到泛型的实际类型。

下面结合例子详细说明可以取到泛型实际类型的三种情况:

在这三种情况中,第一步都是得到一个Type类型或Type数组。

一. 成员变量类型的泛型参数。

Field类下有个Type getGenericType()方法可以获取泛型类,返回类型为Type,代码如下:

Type type = field. getGenericType();

二. 成员方法返回值的泛型参数

Method类下有个Type getGenericReturnType()方法可以获取成员方法返回值的泛型类,返回类型为Type,

Type type = method. getGenericReturnType();

三. 成员方法参数类型的泛型参数,包括构造方法。

Method类下有个Type[] getGenericParameterTypes()方法可以获得成员方法各个参数的泛型类的数组,返回值为Type[],(Constructor类里面也有一个getGenericParameterTypes()方法,也可以使用相同的方式取到构造器参数里的实际泛型参数)代码如下:

Type[] typeArr = method. getGenericParameterTypes();

来源:网易工程师-许小强

有任何问题欢迎留言交流~


整理总结不易,如果觉得这篇文章有意思的话,欢迎转发、收藏,给我一些鼓励~

有想看的内容或者建议,敬请留言!

最近利用空余时间整理了一些精选Java架构学习视频和大厂项目底层知识点,需要的同学欢迎私信我发给你~一起学习进步!有任何问题也欢迎交流~

Java日记本,每日存档超实用的技术干货学习笔记,每天陪你前进一点点~

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值