基础篇:深入解析JAVA泛型和Type类型体系

github地址,感谢star
1 JAVA的Type类型体系
- 先了解下java的Type类型体系(类的类=>类型),Type是所有类型(原生类型-Class、参数化类型-Parameterizedtype、数组类型-GenericArrayType、类型变量-TypeVariable、基本类型-Class)的共同接口;前两篇反射和注解讲到的Class<T>就是Type的一实现类
- Type下面又有四个子接口类ParameterizedType、TypeVariable、GenericArrayType、WildcardType
- List<E>表示泛型,E是TypeVariable类型,List<String>则是ParameterizedType(参数化类型),List<String>里的String称为实际参数类型
- 具体化泛型中的类型时,可以使用 ? extends 或 ? super来表示继承关系;如
List<? extends Data>
,而里面的 ? 称为通配符类型WildcardType - GenericArrayType 表示一种元素类型是ParameterizedType(参数化类型)或者TypeVariable(类型变量)的数组类型,如T[] 或者 List<E>[]
- 注解是JDK1.5才出现了的,为了表示被注解的类型的,加入AnnotatedElement类型,字面意思就是被注解的元素。JDK1.8又有了AnnotatedType将Type和被注解元素的概念关联起来。
- AnnotatedType也有四个子接口,和Type的四个子接口一一对应,如:ParameterizedType类型被注解则被编译器解析成AnnotatedParameterizedType:
@AnTest("list")List<String>list
2 泛型的概念
- Java 泛型(generics)是JDK1.5中引入的一个新特性,其本质是参数化类型,解决不确定具体对象类型的问题;其所操作的数据类型被指定为一个参数(type parameter)这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法
泛型: 把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型
3 泛型类和泛型方法的示例
- 泛型类的定义
- 泛型方法的定义
- 接口和抽象类都可以使用泛型
4 类型擦除
- 创建泛型的实例时,jvm是会把具体类型擦除的;编译生成的字节码中不包含泛型中的类型参数,即ArrayList<String>和ArrayList<Integer>都擦除成了ArrayList,也就是被擦除成"原生类型",这就是泛型擦除
- 查看编译后的字节码文件是如何表示的: idea菜单 -> view -> show ByteCode
- 可以看出T(String)都被转换为Object类型,最初的初始化的String不见了
5 泛型的继承
- 子类可以指定父类的泛型参数,可以是已知类(Integer、String等),也可以用子类自己的泛型参数指定
- 泛型被继承时,且指定父类泛型参数,则额外生成的ParameterizedType类型作为子类的父类;如果没有指定父类泛型参数,则直接继承原生类型
6 泛型变量TypeVariable
- (先临时定义一个名称,Test<E>里的E为泛型参数);泛型变量TypeVariable:泛型的泛型参数就是TypeVariable;当父类使用子类的泛型参数指定自身的泛型参数时;或者泛型属性定义在泛型类A<T>中,并使用泛型类A<T>的泛型参数T时,其泛型参数都会被编译器定为泛型变量TypeVariable,而不是被擦除
7 参数化类型ParameterizedType
- 需要注意的点,我们不能直接获取指定具体参数的泛型的类型,如
Class clazz = List<String>.class
编译时不通过的;还有就是直接通过泛型类new创建的对象,其Class并非ParameterizedType类型,而是泛型本身的class,示例如下
- 被具体参数化的泛型才能被编译器识别为ParameterizedType类型,有三种方式获取ParameterizedType类型
8 通配符(WildcardType)
无边界通配符:无界通配符 ? 可以适配任何引用类型:
- 当方法参数需要传入一个泛型时,而且无法确定其类型时。直接使用无具体泛型变量的泛型,容易造成安全隐患;若在方法代码里进行类型转换,极容易出现ClassCastException错误
- 那泛型变量用Object代替不就行了?但是泛型类+具体参数转变的ParameterizedType(参数化类型)是不存在继承关系;即Object是String的父类,但是List<Object>和List<String>的类型是不同的两个ParameterizedType,不存在继承关系。于是有了类型通配符 ?
- 无界通配符可以匹配任意类型;但是在使用?时,不能给泛型类的变量设置值,因为我们不知道具体类型是什么;如果强行设置新值,后面的读容易出现ClassCastException错误。因此编译器限制了通配符 ?的泛型只能读不能写
上界限定通配符 < ? extends E>
- 想接收一个List集合,它只能操作数字类型的元素【Float、Integer、Double、Byte等数字类型都行】,怎么做?可以使用
List<? extends Number的子类>
,表明List里的元素都是Number的子类
- 图片里可以看出,存在上界通配符,因为具体类型不确定,也是只能读不能写的
下界限定通配符 < ? super E>
- 如果定义了通配符是谁的父类,则是下界限定通配符;此类通配符可读可写,转成任意父类都不会出现ClassCastException错误。
- 个人猜想:难道是因为通配符和上界限定通配符的泛型 向下转型容易出现ClassCastException错误,而下界限定通配符向上转型不会出现ClassCastException错误,因此java规范限制前者编译出错,而后面编译通过?
9 泛型数组(GenericArrayType)
- GenericArrayType,泛型数组,描述的是ParameterizedType类型以及TypeVariable类型数组,即形如:Test<T>[][]、T[]等,是GenericArrayType的子接口
欢迎指正文中错误
关注公众号,一起交流,微信搜一搜: 潜行前行
__EOF__
本文作者:潜行前行
本文链接:https://www.cnblogs.com/cscw/p/13780497.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/cscw/p/13780497.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY